微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用TypeTag和ClassTag在Scala中进行多态实例化

Scala 2.9中,可以实现多态实例化

def newInstance[T](implicit m: Manifest[T]) =
    m.erasure.newInstance.asInstanceOf[T]

但截至2.10 Manifest正在被TypeTag取代,
并且我不清楚如何使用TypeTag实现类似的功能.
如果TypeTag版本保留了所有可用的类型信息,我更愿意.

我知道上面只适用于不需要构造函数args的traits / classes,
然后它并不总是有效,但它足以满足我的需要.
如果我能做得更好,新的反射API会很棒.

解决方法

TypeTag还不是Manifest的替代品,因为它是实验性和不稳定Scala反射的一部分.你现在肯定不应该把它用于生产.

对于你展示的用例,只需要运行时类(不是带有泛型等的完整类型信息),Scala 2.10引入了classtag,你可以这样使用:

def newInstance[T: classtag] =
  implicitly[classtag[T]].runtimeClass.newInstance.asInstanceOf[T]

要么:

def newInstance[T](implicit ct: classtag[T]) =
  ct.runtimeClass.newInstance.asInstanceOf[T]

无论如何,Manifest还没有被弃用,所以我猜你仍然可以使用它.

编辑:

使用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]
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐