如何获取 Scala 函数的参数/返回类型?



我有一个函数,想获得它的参数类型和返回类型,以便在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,我也会坚持使用=符号右侧的<function2>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)

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

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

为了完整起见,当你在Scala REPL中,你可以这样访问类型:

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

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

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

(这里解释了我想在运行时获得变量的类型)

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

相关内容

  • 没有找到相关文章

最新更新