如何获取 Scala 函数的参数/return 类型?
How to get Scala function's parameters / return type?
我有一个函数,想获取它的参数类型和 return 类型以用于 Scala 宏。
scala> val fn = (a: String, b: Double) => 123
fn: (String, Double) => Int = <function2>
scala> fn.getClass
res1: Class[_ <: (String, Double) => Int] = class $anonfun
在上面的示例中,参数类型和 return 类型已经在两行中打印出来,但我不知道如何访问它们。即使使用 toString
我也会被 =
符号右侧的 <function2>
和 class $anonfun
部分卡住——否则可能会进行一些难看的字符串解析。
我发现 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
,(也执行它自己的符号 table 查找)。
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: 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
我有一个函数,想获取它的参数类型和 return 类型以用于 Scala 宏。
scala> val fn = (a: String, b: Double) => 123
fn: (String, Double) => Int = <function2>
scala> fn.getClass
res1: Class[_ <: (String, Double) => Int] = class $anonfun
在上面的示例中,参数类型和 return 类型已经在两行中打印出来,但我不知道如何访问它们。即使使用 toString
我也会被 =
符号右侧的 <function2>
和 class $anonfun
部分卡住——否则可能会进行一些难看的字符串解析。
我发现 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
,(也执行它自己的符号 table 查找)。
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: 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