如何在运行时使用 TypeTags 创建类型 T 的实例 [英] How to create an instance of type T at runtime with TypeTags

查看:26
本文介绍了如何在运行时使用 TypeTags 创建类型 T 的实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是如何在运行时使用 Manifest 创建类型 T 的新实例:

Here below is how to create a new instance of type T at runtime with Manifest:

trait MyTrait
class MyClass1(val name: String) extends MyTrait
class MyClass2(val name: String) extends MyTrait

class Test[T <: MyTrait] {

  def createInstance[T](name: String)(implicit m: Manifest[T]): T = {
    m.runtimeClass.getConstructors()(0)
      .newInstance(name).asInstanceOf[T]
  }

  def doSomething() {
    val myClass = createInstance("joe")
    ...
  }
}

...

val test = new Test[MyClass1]
test.doSomething

上面的 createInstance 方法创建实现 MyTrait 的类之一的新实例,并使用给定的字符串调用构造函数.如何使用 TypeTag 实现相同的功能?

The createInstance method above creates a new instance of one of the classes that implement MyTrait and invokes the constructor with the given string. How do I implement the same with TypeTag?

使用 scala.reflect.runtime._ 重新实现._

以下是按照 som-snytt 的建议重新实现的 Test 类:

Here below is class Test reimplemented as suggested by som-snytt:

class Test[T <: MyTrait] {

  import scala.reflect.runtime._
  import scala.reflect.runtime.universe._

  def createInstance[T: TypeTag](name: String): T = {
    val tt = typeTag[T]

    currentMirror.reflectClass(tt.tpe.typeSymbol.asClass).reflectConstructor(
      tt.tpe.members.filter(m =>
        m.isMethod && m.asMethod.isConstructor
      ).iterator.next.asMethod
    )(name).asInstanceOf[T]
  }   
}

只要我在 Test 上调用 createInstance 它就可以工作:

As long as I call createInstance on Test it works:

val test = new Test[MyClass1]
val myClass = test.createInstance("hello") // this works

但是一旦我定义了一个从 Test 派生的新类...

But as soon as I define a new class derived from Test...

class DerivedTest[T <: MyTrait] extends Test[T]

...然后我像这样在那个新类上调用 createInstance...

... and I invoke createInstance on that new class like this...

val test = new DerivedText[MyClass1]
val myClass = test.createInstance("hello") // this crashes

...我收到以下错误:

... I get the following error:

java.util.NoSuchElementException: next on empty iterator
    at scala.collection.Iterator$$anon$2.next(Iterator.scala:39)
    at scala.collection.Iterator$$anon$2.next(Iterator.scala:37)
    at scala.collection.LinearSeqLike$$anon$1.next(LinearSeqLike.scala:62)
    at DerivedTest$class.createInstance(<console>:27)
    at $anon$1.createInstance(<console>:26)
    at .<init>(<console>:28)
at .<clinit>(<console>)
    at .<init>(<console>:7)
    at .<clinit>(<console>)
    at $print(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
...

我错过了什么吗?

推荐答案

最终这里是实际工作的实现 - 请假设这个答案来自 som-snytt:

Eventually here is the implementation that actually works - please just assume this answer comes from som-snytt:

import scala.reflect.runtime._
import scala.reflect.runtime.universe._

class Test[T <: MyTrait : TypeTag] {

  def createInstance(args: AnyRef*)(ctor: Int = 0): T = {
    val tt = typeTag[T]

    currentMirror.reflectClass(tt.tpe.typeSymbol.asClass).reflectConstructor(
      tt.tpe.members.filter(m =>
        m.isMethod && m.asMethod.isConstructor
      ).iterator.toSeq(ctor).asMethod
    )(args: _*).asInstanceOf[T]
  }   
}

希望能帮到你.

这篇关于如何在运行时使用 TypeTags 创建类型 T 的实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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