TypeTag
non è ancora un sostituto per Manifest
perché è una parte della riflessione Scala sperimentale e instabile. Sicuramente non dovresti usarlo per la produzione fin d'ora.
Per il caso d'uso che ha mostrato, in cui è necessario unica classe runtime (non informazioni di tipo completo con i generici, ecc), Scala 2.10 introdotte ClassTag
, che è possibile utilizzare in questo modo:
def newInstance[T: ClassTag] =
implicitly[ClassTag[T]].runtimeClass.newInstance.asInstanceOf[T]
o:
def newInstance[T](implicit ct: ClassTag[T]) =
ct.runtimeClass.newInstance.asInstanceOf[T]
In ogni caso, Manifest
non è ancora deprecato, quindi suppongo che tu possa ancora usarlo.
EDIT:
Utilizzando TypeTag
per ottenere lo stesso:
import scala.reflect.runtime.universe._
def newInstance[T: TypeTag] = {
val clazz = typeTag[T].mirror.runtimeClass(typeOf[T])
clazz.newInstance.asInstanceOf[T]
}
La soluzione di cui sopra utilizza ancora qualche riflessione Java. Se vogliamo essere purista e utilizzare solo Scala di riflessione, questa è la soluzione:
def newInstance[T: TypeTag]: T = {
val tpe = typeOf[T]
def fail = throw new IllegalArgumentException(s"Cannot instantiate $tpe")
val noArgConstructor = tpe.member(nme.CONSTRUCTOR) match {
case symbol: TermSymbol =>
symbol.alternatives.collectFirst {
case constr: MethodSymbol if constr.paramss == Nil || constr.paramss == List(Nil) => constr
} getOrElse fail
case NoSymbol => fail
}
val classMirror = typeTag[T].mirror.reflectClass(tpe.typeSymbol.asClass)
classMirror.reflectConstructor(noArgConstructor).apply().asInstanceOf[T]
}
Grazie @ghik, sarei ancora interessati a scoprire come farlo con typetag, preferibilmente conservando informazioni complete tipo, vale a dire l'inferenza di tipo dovrebbe dedurre 'newInstance [MyClass {Int]]: MyClass [Int] ' –
@DanielMahler Ho aggiunto la soluzione basata su 'TypeTag'. Si prega di consultare la mia modifica. – ghik
@ghik quando si utilizza 'runtimeMirror (this.getClass.getClassLoader)' è possibile ottenere un'eccezione quando 'T' non è caricato con lo stesso classloader di' this.type'. Dovresti usare un mirror collegato a 'TypeTag':' typeTag [T] .mirror'. –