Scala 中使用 TypeTag 和 ClassTag 的多态实例化 [英] Polymorphic instantiation in Scala using TypeTag and ClassTag

查看:204
本文介绍了Scala 中使用 TypeTag 和 ClassTag 的多态实例化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In Scala 2.9 one could implement polymorphic instantiation as

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

但从 2.10 开始,Manifest 被替换为 TypeTag,我不清楚如何使用 TypeTag 实现类似的功能.我希望 TypeTag 版本保留所有可用的类型信息.

but as of 2.10 Manifest is being replaced with TypeTag, and it is not clear to me how to achieve something similar with TypeTag. I would prefer if the TypeTag version preserved all available type information.

我知道以上仅适用于不需要构造函数参数的特征/类,然后它并不总是有效,但它足以满足我的需要.如果我能把新的反射 API 做得更好,那就太好了.

I know that the above only works for traits/classes that do not require constructor args, and ven then it does not always work, but it works well enough for what I need. If I can do better the new reflection APIs that would be great.

推荐答案

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

TypeTag is not yet a replacement for Manifest because it's a part of experimental and unstable Scala reflection. You definitely shouldn't use it for production as of now.

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

For the use case you showed, where only runtime class is needed (not full type information with generics etc.), Scala 2.10 introduced ClassTag, which you can use like this:

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

或:

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

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

Anyway, Manifest isn't deprecated yet, so I guess you can still use it.

使用 TypeTag 实现相同的效果:

Using TypeTag to achieve the same:

import scala.reflect.runtime.universe._

def newInstance[T: TypeTag] = {
  val clazz = typeTag[T].mirror.runtimeClass(typeOf[T])
  clazz.newInstance.asInstanceOf[T]
}

上面的解决方案仍然使用了一些Java反射.如果我们想要纯粹并且只使用 Scala 反射,这就是解决方案:

The above solution still uses some Java reflection. If we want to be puristic and use only Scala reflection, this is the solution:

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

这篇关于Scala 中使用 TypeTag 和 ClassTag 的多态实例化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆