在 Scala 2.9 中,可以将多态实例化实现为
def newInstance[T](implicit m: Manifest[T]) =
m.erasure.newInstance.asInstanceOf[T]
但从2.10开始Manifest
正在被替换为TypeTag
,
我不清楚如何实现类似的目标TypeTag
。
我希望 TypeTag 版本保留所有可用的类型信息。
我知道上面的内容仅适用于不需要构造函数参数的特征/类,
即使如此,它并不总是有效,但它足以满足我的需要。
如果我能在新的反射 API 上做得更好,那就太好了。
TypeTag
尚未替代Manifest
因为它是实验性且不稳定的 Scala 反射的一部分。目前你绝对不应该将它用于生产。
对于您展示的用例,仅需要运行时类(不需要泛型等的完整类型信息),Scala 2.10 引入了ClassTag
,你可以这样使用:
def newInstance[T: ClassTag] =
implicitly[ClassTag[T]].runtimeClass.newInstance.asInstanceOf[T]
or:
def newInstance[T](implicit ct: ClassTag[T]) =
ct.runtimeClass.newInstance.asInstanceOf[T]
Anyway, Manifest
尚未弃用,所以我想您仍然可以使用它。
EDIT:
Using TypeTag
达到同样的目的:
import scala.reflect.runtime.universe._
def newInstance[T: TypeTag] = {
val clazz = typeTag[T].mirror.runtimeClass(typeOf[T])
clazz.newInstance.asInstanceOf[T]
}
上面的解决方案仍然使用了一些Java反射。如果我们想要纯粹并只使用 Scala 反射,这就是解决方案:
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]
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)