斯卡拉。如何在类继承中推断泛型类型

时间:2017-07-25 09:21:08

标签: scala reflection macros

我有两个班级:

class Base[A]{
    def doSome:A
}

class StringImpl extends Base[String]

如何推断(没有清单,只有反射分析)类StringImpl中的泛型类型是String? (在实际情况下,遗传结构可能更复杂,例如)

2 个答案:

答案 0 :(得分:3)

使用scala运行时反射(isInstanceOf不适用于已删除的类型 - 它始终返回true):

typeOf[StringImpl] <:< typeOf[Base[String]] //true 
typeOf[StringImpl] <:< typeOf[Base[Int]] //false

请参阅:http://www.scala-lang.org/api/2.11.7/scala-reflect/#scala.reflect.api.Types $ TypeApi

val tp = typeOf[StringImpl]
tp.baseType(tp.baseClasses(1)).typeArgs
res17_4: List[reflect.runtime.package.universe.Type] = List(String)

它允许您访问类型参数等以获得更复杂的案例。

更新。对于ClassSymbol,您可以使用typeSignature方法:

tp.typeSymbol.typeSignature

res19_5: reflect.runtime.package.universe.Type = Helper.this.Base[String] {
  def <init>(): Helper.this.StringImpl
  def doSome: String
}

另外,对于宏(如果你不想要明显的WeakTypeTag解决方案):

 import c.universe._
 val TypeApply(_, List(typeTree)) = c.macroApplication
 //you can analyze typeTree here

Scala: Get type name without runtime reflection and without type instance

一般答案

通用类型在JVM中被擦除,因此默认情况下在运行时没有存储信息 - 在一般情况下,没有ClassTag / TypeTag在运行时“物理上”无法获取擦除类型(只能在子类中探索方法/成员签名)这样的存在)。但是,您始终可以进行编译时检查,例如:

abstract class Base{
   type A
   def doSome:A
}

class StringImpl extends Base{
   type A = String
   def doSome:A = "aaa"

}

implicitly[StringImpl#A =:= String]

答案 1 :(得分:0)

我认为你可以获得doSome方法返回类型的通用类型 A 没有清单(因为没有访问类),例如:

new StringImpl().getClass.getMethod("doSome").getReturnType.getSimpleName
> String