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

时间:2018-06-25 10:04:27

标签: scala reflection guice

如何使用反射在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](...))。

2 个答案:

答案 0 :(得分:1)

您可以尝试创建一个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
}

答案 1 :(得分:0)

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