在Scala 2.10中通过反射查找类型参数?

22

通过使用类型标签,我能够看到某些类型的参数:

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

scala> typeOf[List[Int]]
res0: reflect.runtime.universe.Type = List[Int]

但是我无法找到一种通用的程序化方法来获取那个" Int "。 (我已经在REPL中徘徊了一个小时,尝试对类型进行排列组合,看看能从中获得什么...我得到了许多指示这是一个“列表”,但祝您好运找到那个“Int”!而且我不想采用解析toString()输出的方法...)Daniel Sobral在这里提供了一个出色的(像往常一样)快速概述,他非常接近我所寻找的东西,但只有在您知道该特定类的某些特定方法可以被询问的情况下才能实现。

scala> res0.member(newTermName("head"))
res1: reflect.runtime.universe.Symbol = method head

scala> res1.typeSignatureIn(res0)
res2: reflect.runtime.universe.Type = => Int

但我希望有更通用的方法,不需要深入查找声明方法并希望其中一个方法捕获(从而泄露)标记的当前类型信息。

如果Scala可以如此轻松地“打印”“List[Int]”,为什么很难发现那个“Int”部分——而不使用字符串模式匹配呢?或者我是不是漏掉了一些非常显然的东西?

scala> res0.typeSymbol.asInstanceOf[ClassSymbol].typeParams
res12: List[reflect.runtime.universe.Symbol] = List(type A)

scala> res12.head.typeSignatureIn(res0)
res13: reflect.runtime.universe.Type = 

咕噜...


这里是一个非答案:至少使用M7,您可以通过将其转换为内部API来获取类型参数:typeOf [List [Int]] .asInstanceOf [scala.reflect.internal.Types $ TypeApiImpl] .typeArguments - Travis Brown
2个回答

16

从Scala 2.11版本开始,您可以直接使用以下代码:

yourGenericType.typeArgs.head

请查看宏变更日志第14点。


14

不幸的是,我认为没有一种方法可以直接给出参数,但您可以通过以下方式获取它们:

Welcome to Scala version 2.10.0-20121007-145615-65a321c63e (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_35).
Type in expressions to have them evaluated.
Type :help for more information.

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

scala> typeOf[List[Int]]
res0: reflect.runtime.universe.Type = scala.List[Int]

scala> res0 match { case TypeRef(_, _, args) => args }
res1: List[reflect.runtime.universe.Type] = List(Int)

scala> res1.head
res2: reflect.runtime.universe.Type = Int

编辑 以下是一种稍微更好的实现方式(参考 scala-internals 上的讨论):

scala> res0.asInstanceOf[TypeRefApi].args
res1: List[reflect.runtime.universe.Type] = List(Int)

这个问题在scala-internals邮件列表中讨论过,链接在这里:https://groups.google.com/forum/#!msg/scala-internals/R1iZXfotqds/zqq8QjMJj74J - Paul Butcher
1
对于这种情况,我更喜欢这样写:'val TypeRef(_, _, tpe :: Nil) = typeOf[List[Int]]'。 - Alois Cochard
请问你是如何导入TypeRefApi和/或TypeRef的?无论我尝试导入什么,都无法编译。 - Ryan
更新:我解决了导入问题(之前从另一个示例中导入了不同的内容),但现在我遇到了一个类型转换错误。问题在于我正在使用member.typeSignature(即尝试在运行时找到的成员上进行此操作,而不是在编译时已知的类上进行此操作),虽然它也返回runtime.universe.Type,但似乎是一个不同的实现,无法强制转换为TypeRefApi。所以我还是卡住了。 - Ryan
更新:我在http://stackoverflow.com/questions/22802541/how-do-i-get-the-declared-generic-parameter-of-the-type-of-a-member-found-at-r上回答了自己的问题。 - Ryan
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接