2009-05-04 7 views
16

Sto cercando di scrivere del codice Scala che ha bisogno di fare qualcosa di simile:Tipi astratti/Tipo I parametri in Scala

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

e sta fallendo. Ovviamente non sto capendo qualcosa sui parametri generici di Scala. Chiaramente, l'equivoco è che in C++ i template funzionano essenzialmente come sostituzioni di stringhe, quindi il nuovo Type() funzionerà fintanto che la classe che viene passata ha un costruttore predefinito. Tuttavia, in Scala, i tipi sono diversi tipi di oggetti.

+0

Che cos'è una domanda? – stepancheg

+0

Come posso fare questo lavoro? – bsdfish

risposta

28

Come si fa notare, C++ ha modelli. In breve, il C++ dice "esiste un test per tutti i tipi T tale che compaia il test". Ciò semplifica implicitamente l'aggiunta di vincoli su T, ma dal lato negativo sono impliciti e potrebbero essere difficili da comprendere per un utente della classe senza leggere il codice.

Il polimorfismo parametrico di Scala (ovvero generici) funziona molto più come ML, Haskell, Java e C#. In Scala, quando scrivi "class Test [T]" stai dicendo "per tutti i T esiste un tipo Test [T]" senza vincoli. È più semplice ragionare formalmente, ma vuol dire che devi essere esplicito riguardo ai vincoli. Ad esempio, in Scala puoi dire "class Test [T <: Foo]" per dire che T deve essere un sottotipo di Foo.

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

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

Il modo typesafe sembra

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

Poi si può avere un corpo di fabbriche per i tipi di utili nel vostro 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 vostra biblioteca hanno bisogno le loro fabbriche poi si possono aggiungere il proprio equivalente dell'oggetto Factories. Un vantaggio di questa soluzione è che qualsiasi cosa con una fabbrica può essere utilizzata, indipendentemente dal fatto che ci sia o meno un costruttore no-arg.

Il modo non-così-typesafe utilizza la riflessione e una caratteristica in Scala chiamato manifesti che sono un modo per aggirare un vincolo di Java per quanto riguarda la cancellazione di tipo

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

Con questa versione è ancora scrivere

class Foo 
val t = new Test[Foo] 

Tuttavia, se non c'è nessun costruttore no-arg disponibili 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) 
+0

Uno di questi approcci funziona con i costruttori basati su parametri per T? –