【问题标题】:How to reflect concrete return types for methods of classes defined at runtime using the Scala ToolBox?如何使用 Scala 工具箱反映在运行时定义的类方法的具体返回类型?
【发布时间】:2020-11-12 05:44:48
【问题描述】:

当反射Cls类的foo()方法时,我们可以很容易地使用下面的方法得到具体的返回类型。

class Cls {
  def foo() =
    List("A", "B")
}

val classType = ru.typeOf[Cls]
val classMirror = toolbox.mirror.reflectClass(classType.typeSymbol.asClass)
val ctorSymbol = classType.decl(ru.termNames.CONSTRUCTOR).asMethod
val methodSymb = classType.decl(ru.TermName("foo")).asMethod
val ctor = classMirror.reflectConstructor(ctorSymbol)
val instance = ctor()
val im = toolbox.mirror.reflect(instance)
val foo = im.reflectMethod(methodSymb)
println(foo())  // List(A, B)
println(methodSymb.returnType) // List[String]

但是,如果我们在运行时通过工具箱定义类Cls,然后使用相同的方法反射过程,我们只会得到foo()方法的抽象返回类型(List)。

import ru._

val tree =
  q"""class Cls {
        def foo() =
          List("A", "B")
    }""".asInstanceOf[ru.ClassDef]

val classSymbol = toolbox.define(tree).asClass
val classType = classSymbol.selfType

val classMirror = toolbox.mirror.reflectClass(classType.typeSymbol.asClass)
val ctorSymbol = classType.decl(ru.termNames.CONSTRUCTOR).asMethod
val methodSymb = classType.decl(ru.TermName("foo")).asMethod
val ctor = classMirror.reflectConstructor(ctorSymbol)
val instance = ctor()
val im = toolbox.mirror.reflect(instance)
val foo = im.reflectMethod(methodSymb)
println(foo())  // List("A", "B")
println(methodSymb.returnType)  // List

为什么这些代码sn-ps会产生不同的结果?

如果在运行时使用工具箱定义了Cls,我们如何反映foo()方法的具体返回类型?

【问题讨论】:

    标签: scala reflection scala-reflect


    【解决方案1】:

    我猜是类型擦除。

    尝试替换

    val classType = classSymbol.selfType
    

    val classType = toolbox.eval(q"scala.reflect.runtime.universe.typeOf[$classSymbol]").asInstanceOf[ru.Type]
    

    那么methodSymb.returnType 就是List[String]

    【讨论】:

    • 感谢您的修复!您是否愿意分享更多详细信息(或指向文档的指针)来解释为什么这两个选项之间的类型擦除会有所不同?无论哪种方式都接受。
    • @Erp12 好吧,我不是 100% 确定(有必要更深入地调试工具箱代码生成),但我的猜测如下。让我们考虑一下代码工作流程。主要代码有编译时间和运行时间。在主代码运行时中的工具箱中,出现了工具箱的编译时间和运行时。在工具箱编译时返回类型为List[String],在工具箱运行时返回类型为List[_],因为已擦除。
    • @Erp12 我怀疑当我们执行classSymbol.selfType 时,我们在工具箱运行时工作,而使用toolbox.eval(q"scala.reflect... 我们从工具箱编译时捕获一个类型(tb.eval(tree)tb.compile(tree).apply())。 Toolbox 不允许控制更好的代码生成。我想通过手动代码生成(参见question 中的code),您可以更好地控制编译和运行代码的方式。
    • @Erp12 在那个问题中,我已经遇到了一种情况,我必须使用 eval 从工具箱中捕获一些类型信息(请参阅我对 tb.eval(q"...TypeInformation.of(classOf... 的回答中的代码 sn-p )。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-03
    • 1970-01-01
    • 2019-04-22
    • 2010-11-06
    • 1970-01-01
    • 2019-06-06
    • 1970-01-01
    相关资源
    最近更新 更多