Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用TypeTag和ClassTag在Scala中进行多态实例化_Scala_Reflection_Scala 2.10 - Fatal编程技术网

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

使用TypeTag和ClassTag在Scala中进行多态实例化,scala,reflection,scala-2.10,Scala,Reflection,Scala 2.10,在Scala2.9中,可以实现多态实例化 def newInstance[T](implicit m: Manifest[T]) = m.erasure.newInstance.asInstanceOf[T] 但从2.10开始,清单将被类型标签取代, 我不清楚如何使用TypeTag实现类似的功能。 我希望TypeTag版本保留所有可用的类型信息 我知道以上只适用于不需要构造函数参数的特征/类, 即使这样,它也不总是有效的,但它对我所需要的足够有效。 如果我能做得更好的话,新的反射API

在Scala2.9中,可以实现多态实例化

def newInstance[T](implicit m: Manifest[T]) =
    m.erasure.newInstance.asInstanceOf[T]
但从2.10开始,清单将被类型标签取代, 我不清楚如何使用
TypeTag
实现类似的功能。 我希望TypeTag版本保留所有可用的类型信息

我知道以上只适用于不需要构造函数参数的特征/类, 即使这样,它也不总是有效的,但它对我所需要的足够有效。
如果我能做得更好的话,新的反射API就太棒了。

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

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

def newInstance[T: ClassTag] =
  implicitly[ClassTag[T]].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]
}

如果您想支持传递args,下面是我在2.11中的一个技巧:

def newInstance[T : ClassTag](init_args: AnyRef*): T = {
classTag[T].runtimeClass.getConstructors.head.newInstance(init_args: _*).asInstanceOf[T]
}
用法示例:

scala> case class A(x:Double, y:Int)
defined class A
scala> newInstance[A](4.5.asInstanceOf[Object],3.asInstanceOf[Object])
res1: A = A(4.5,3)

感谢@ghik,我仍然有兴趣了解如何使用TypeTag,最好是在保留完整类型信息的同时,即类型推断应该推断
newInstance[MyClass{Int]]:MyClass[Int]
@DanielMahler我添加了基于
TypeTag
的解决方案。请在使用
runtimeMirror时查看我的编辑。@ghik(this.getClass.getClassLoader)
如果
T
没有使用与
this.type
相同的类加载器加载,则会出现异常。您应该使用附加到
TypeTag
的镜像:
TypeTag[T]。mirror
scala> case class A(x:Double, y:Int)
defined class A
scala> newInstance[A](4.5.asInstanceOf[Object],3.asInstanceOf[Object])
res1: A = A(4.5,3)