Domanda

Sto cercando di scrivere del codice Scala che deve fare qualcosa del tipo:

class Test[Type] { 
   def main {
       SomeFunc classOf[Type]
       val testVal: Type = new Type()
    }
 }

e non riesce. Ovviamente non capisco qualcosa sui parametri generici di Scala. Chiaramente, il malinteso è che in C ++ i template funzionano essenzialmente come sostituzioni di stringhe, quindi new Type () funzionerà fintanto che la classe che viene passata ha un costruttore predefinito. Tuttavia, in Scala, i tipi sono diversi tipi di oggetti.

È stato utile?

Soluzione

Come fai notare, C ++ ha dei template. In breve, C ++ dice & Quot; esiste un Test per tutti i tipi T in modo che Test compili. & Quot; Ciò rende facile aggiungere implicitamente vincoli su T, ma sul lato negativo sono impliciti e possono essere difficili da comprendere per un utente della tua classe senza leggere il codice.

Il polimorfismo parametrico di Scala (alias generici) funziona molto di più come ML, Haskell, Java e C #. In Scala, quando scrivi & Quot; class Test [T] & Quot; stai dicendo " per tutte le T esiste un tipo Test [T] " senza vincolo. È più semplice ragionare formalmente, ma significa che devi essere esplicito sui vincoli. Ad esempio, in Scala puoi dire & Quot; class Test [T & Lt ;: Foo] & Quot; per dire che T deve essere un sottotipo di Foo.

C # ha un modo per aggiungere un vincolo a T per quanto riguarda i costruttori, ma sfortunatamente Scala no.

Ci sono un paio di modi per risolvere il tuo problema in Scala. Uno è typesafe ma un bt più dettagliato. L'altro non è dattiloscritto.

Il tipo di dattiloscritto appare come

class Test[T](implicit val factory : () => T) {
  val testVal = factory
}

Quindi puoi avere una serie di fabbriche per tipi utili nel tuo sistema

object Factories {
  implicit def listfact[X]() = List[X]()
  implicit def setfact[X]() = Set[X]()
  // etc
}

import Factories._
val t = new Test[Set[String]]

Se gli utenti della tua biblioteca hanno bisogno delle proprie fabbriche, possono aggiungere il loro equivalente dell'oggetto Fabbriche. Un vantaggio di questa soluzione è che qualsiasi cosa con una fabbrica può essere utilizzata, indipendentemente dal fatto che esista o meno un costruttore no-arg.

Il modo non tipicamente tipografico usa la riflessione e una caratteristica in Scala chiamata manifest, che è un modo per aggirare un vincolo Java relativo alla cancellazione del tipo

 class Test[T](implicit m : Manifest[T]) {
   val testVal = m.erasure.newInstance().asInstanceOf[T]
 }

Con questa versione scrivi ancora

class Foo
val t = new Test[Foo]

Tuttavia, se non è disponibile alcun costruttore no-arg, si ottiene un'eccezione di runtime invece di un errore di tipo statico

scala> new Test[Set[String]] 
java.lang.InstantiationException: scala.collection.immutable.Set
at java.lang.Class.newInstance0(Class.java:340)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top