如何在 Scala 中反射性地参数化泛型类型?

How to reflectively parameterise a generic type in Scala?

如何使用反射在 Scala 中实现以下伪代码?

为了从 Guice 中查找通用类型,我需要这个:

trait Foo[A]
class FooInt extends Foo[Int]
class FooString extends Foo[String]

bind(new TypeLiteral<Foo<Int>>() {}).to(FooInt.class);

def fooTypeLiteral(paramA: Class[_]): TypeLiteral[_] = ???

val foo = injector.getInstance(fooTypeLiteral(classOf[Int])
// foo: FooInt

注意:我在编译时无法访问A的类型,因此_。整个解决方案需要反思执行(例如,我不能 parameterizeFoo[A : ClassTag](...))。

Scala 和 Java 编译器都实现了带有类型擦除的泛型。这意味着当源代码转换为 JVM 字节码时,泛型子类型的所有类型信息都会丢失。如果通用 class 本身不包含 ClassTag 或类似的嵌入信息,那么您无法在 运行 时获得 class。

您可以尝试创建一个 ParameterizedType 并将其传递给 TypeLiteral 的工厂方法:

def fooTypeLiteral(paramA: Class[_]): TypeLiteral[_] = {
  TypeLiteral.get(new java.lang.reflect.ParameterizedType() {
    def getRawType = classOf[Foo[_]]
    def getOwnerType = null
    def getActualTypeArguments = Array(paramA)
  })
}

如果您只有有限数量的 Foo 实现,您可以试试这个:

trait Foo[A]
class FooInt extends Foo[Int]
class FooString extends Foo[String]

val TLFI = new TypeLiteral[Foo[Int]](){}
val TLFS = new TypeLiteral[Foo[String]](){}

bind(TLFI).to(FooInt.class);
bind(TLFS).to(FooString.class);

def fooTypeLiteral(c: Class[_]): TypeLiteral[_] = {
  if (c == classOf[Int]) TLFI
  else if (c == classOf[String]) TLFS
  else throw new Error
}