【问题标题】:Finding type parameters via reflection in Scala 2.10?在 Scala 2.10 中通过反射查找类型参数?
【发布时间】:2012-10-11 15:06:07
【问题描述】:

使用类型标签,我可以看到某种类型的参数:

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

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

但我只是不太清楚如何以编程方式以一般方式将“Int”从那里取出。

(我已经在 REPL 中徘徊了一个小时,尝试对 Type 进行排列,看看我能从中获得什么……我得到了很多东西表明这是一个“列表”,但很好找到那个“Int”的运气!而且我真的不想求助于解析 toString() 输出......)

Daniel Sobral 对here 进行了出色的(和往常一样)快速概览,其中他非常接近我正在寻找的内容,但(显然)只有当你碰巧知道,对于那个特定的课程,一些特定的可以查询类型的方法:

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

标签: scala reflection scala-2.10


【解决方案1】:

Scala 2.11开头,你可以简单地使用:

yourGenericType.typeArgs.head

请参阅macros changelog 点号 14。

【讨论】:

    【解决方案2】:

    遗憾的是,我认为没有一种方法可以为您提供参数,但您可以通过这种方式获取它们:

    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
    

    编辑 这是实现相同目标的更好方法(遵循discussion on scala-internals):

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

    【讨论】:

    • 这在 scala-internals 邮件列表中讨论过:groups.google.com/forum/#!msg/scala-internals/R1iZXfotqds/…
    • 看来可以! - 虽然(参考您的链接)我也分享您的不安!我将在这里以我自己的经验作为论据,说明为什么这违反了最小惊讶原则。
    • 感谢您的更新!老实说,如果我刚刚在某个地方遇到了文档(“嘿,使用提取器...”)——也许在 Universe 的(当前为空的)文档中,我会马上明白的。但我没有意识到你必须使用提取器将所有东西都拉出来。 (通常情况下,每个提取器都有一个字段......而我们曾经是 Java 的人并不总是记得这种可能性。)谷歌也没有透露任何有用的信息。
    • 对于这种特殊情况,我更喜欢这样写:'val TypeRef(_, _, tpe :: Nil) = typeOf[List[Int]]'
    • 您能告诉我您是如何导入 TypeRefApi 和/或 TypeRef 的吗?无论我尝试导入什么,我都无法编译它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多