【问题标题】:How to get Scala function's parameters / return type?如何获取 Scala 函数的参数/返回类型?
【发布时间】:2015-09-06 03:47:57
【问题描述】:

我有一个函数,想获取它的参数类型和返回类型,以便在 Scala 宏中使用。

scala> val fn = (a: String, b: Double) => 123
fn: (String, Double) => Int = <function2>

scala> fn.getClass
res1: Class[_ <: (String, Double) => Int] = class $anonfun$1

在上面的例子中,参数类型和返回类型已经在两行打印出来了,但我不知道如何访问它们。即使使用toString,我也会被= 符号右侧的&lt;function2&gt;class $anonfun$1 部分困住——否则可能会进行一些难看的字符串解析。

我发现MethodSymbolApi 提供了一种为方法提取此信息的方法,但对于这种特殊情况,这似乎没有帮助。

我目前正在研究 AST 解析(作为scala.meta 的一部分)以提取信息,但我认为这个问题似乎足够基本,可以被标准反射库涵盖,尽管我未能在那里找到我想要的东西。有什么想法吗?

根据@johanandren 的回答进行编辑:

我还没有找到一种更简洁的方法来从 TypeTag/Type 中提取它们,但这确实有效。 :)

scala> val fn = (a: String, b: Double) => 123
scala> import scala.reflect.runtime.{universe => ru}
scala> def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]
scala> getTypeTag(fn).tpe.toString.split(" => ")
res179: Array[String] = Array((String, Double), Int)

【问题讨论】:

    标签: scala reflection anonymous-function scala-macros


    【解决方案1】:

    getClass 是 Java 反射 API 的一部分,它不太了解 Scala 类型,您应该查看 Scala Reflection API。这应该让你开始,http://docs.scala-lang.org/overviews/reflection/overview.html

    不确定,但我认为函数类型的 TypeTag 是您想要的。

    【讨论】:

    • 谢谢;将在此处粘贴工作输出,但它不会格式化为代码,因此现在将其添加到问题中。
    • 所以,A =&gt; R 等实际上是具体类的语法糖 - Function1[A, R]Function2[A, B, R] 等,因此您可以通过获取最后一个来访问作为返回值的类型参数,像这样typeTag.tpe.typeArgs.last
    • 注意:参数提取可以使用.init而不是.last
    • 对不起,我以为你只是出于某种奇怪的原因才追求返回值 :)
    【解决方案2】:

    为了完整起见,当您在 Scala REPL 中时,您可以将类型访问为:

    scala> val fn = (a: String, b: Double) => 123
    fn: (String, Double) => Int = <function2>
    
    scala> :type fn
    (String, Double) => Int
    

    在运行时,Scala 编译器不会有完整的类型信息。所以它形成了一个代码 sn-p fn,(也做它自己的符号表查找)。 https://github.com/scala/scala/blob/v2.10.5/src/compiler/scala/tools/nsc/interpreter/ILoop.scala#L449

    然后将其传递给编译器,然后编译器将类型信息附加到 implicit evidence 类型。

    (这里解释I want to get the type of a variable at runtime

    scala> import scala.reflect.runtime.universe.{TypeTag, typeTag}
    import scala.reflect.runtime.universe.{TypeTag, typeTag}
    
    scala> def getTypeTag[T: TypeTag](obj: T) = typeTag[T]
    getTypeTag: [T](obj: T)(implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.TypeTag[T]
    

    现在我们有证据可以为我们提供确切的类型信息:

    scala> getTypeTag(fn)
    res0: reflect.runtime.universe.TypeTag[(String, Double) => Int] = TypeTag[(String, Double) => Int]
    
    scala> val targs = res0.tpe.typeArgs
    targs: List[reflect.runtime.universe.Type] = List(String, Double, Int)
    

    现在我们可以轻松访问这些类型了:

    scala> val (in, out) = (ta.init, ta.last)
    in: List[reflect.runtime.universe.Type] = List(String, Double)
    out: reflect.runtime.universe.Type = Int
    
    scala> println(s"INPUTS: $in")
    INPUTS: List(String, Double)
    
    scala> println(s"OUTPUT: $out")
    OUTPUT: Int
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-14
      • 2016-07-01
      • 2018-11-06
      • 1970-01-01
      • 1970-01-01
      • 2014-05-29
      • 2018-08-10
      • 2011-02-14
      相关资源
      最近更新 更多