【问题标题】:How can you tell if a Scala object is a function?如何判断 Scala 对象是否是函数?
【发布时间】:2014-05-22 21:58:03
【问题描述】:

Scala 的反射 API 是否提供了一种判断 Scala 对象是否为函数的方法?到目前为止,我想出的最好的是:

import scala.reflect.runtime.universe._

def isFunction[T : TypeTag](x: T) =
  weakTypeOf[T] <:< weakTypeOf[Function0[_]] ||
  weakTypeOf[T] <:< weakTypeOf[Function1[_,_]] ||
  weakTypeOf[T] <:< weakTypeOf[Function2[_,_,_]] ||
  weakTypeOf[T] <:< weakTypeOf[Function3[_,_,_,_]] ||
  weakTypeOf[T] <:< weakTypeOf[Function4[_,_,_,_,_]] ||
  . . .

必须有更好的方法。

【问题讨论】:

  • 它们没有共同的超类型,所以不,我认为你不能更简洁地做到这一点。你为什么想知道??
  • 我正在编写一个小玩意儿来将函数连接到其他函数,基于它们提供其他函数所需类型值的能力(有点像 make,但是对于值和函数而不是文件和命令)。如果我能说,“这是一个函数吗?好的,它采用什么参数类型,它返回什么类型?”
  • 你说的是 Scala 中的 andThen 构造吗?
  • 我可能最终会调用andThen,但首先我需要查看哪些对象是函数并检查它们的类型签名。或者,嗯,既然你提到了它,也许我可以打电话给andThen,如果出现问题,我可以捕获一个异常……(不,这听起来很麻烦。)
  • 使用类型系统,而不是反射。

标签: scala reflection


【解决方案1】:
10:21 ~/Projects/210x/sandbox (2.10.x)$ scala
Welcome to Scala version 2.10.5-20140407-165700-ec05aeb3d6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_40).

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

scala> definitions.FunctionClass.contains(typeOf[Function1[_, _]].typeSymbol)
res1: Boolean = true

10:22 ~/Projects/211x/sandbox (2.11.x)$ scala
Welcome to Scala version 2.11.1-20140509-211642-d079e769b9 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_40).

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

scala> definitions.FunctionClass.seq.contains(typeOf[Function1[_, _]].typeSymbol)
res0: Boolean = true

【讨论】:

  • 令我惊讶的是,这行得通:def isFunction[T : TypeTag](x: T): Boolean = definitions.FunctionClass.seq.contains(weakTypeOf[T].typeSymbol) 即使我正在传递具有指定类型参数的函数。我在DefinitionsApi 上找到了2.10.4 documentation,其中包括FunctionClass。是否有 2.11 的文档解释了为什么需要 .seq
  • 我刚刚找到了2.11.1 documentation。那么VarArityClassApi 是否会使用某种魔法来处理任何数量的函数?
【解决方案2】:

据我所知,公共 API 不允许您这样做,但始终可以访问内部:

scala> val st = scala.reflect.runtime.universe.asInstanceOf[scala.reflect.runtime.JavaUniverse]
st: scala.reflect.runtime.JavaUniverse = scala.reflect.runtime.JavaUniverse@db03ddc

scala> st.definitions.isFunctionType(st.typeOf[Int])
res0: Boolean = false

scala> st.definitions.isFunctionType(st.typeOf[Int => Int])
res1: Boolean = true

scala> st.definitions.isFunctionType(st.typeOf[Function0[Int]])
res2: Boolean = true

scala> st.definitions.isFunctionType(st.typeOf[Function0[_]])
res3: Boolean = true

【讨论】:

  • 非常有趣。我刚试了一下,效果很好!幸运的是,我认为我不需要未指定类型参数的情况。
  • 有一个公共的 API。 definitions 包含许多可以检查的重要符号。
  • 顺便说一句,仅当您转换为 scala.reflect.internal.SymbolTable 时才会发生崩溃,因为运行时反射无法选择正确的类加载器(包含 $iw 的类加载器)并推测性地使用已加载的类加载器scala-library.jar.
  • 只有当 typeOf 调用的前缀是 scala.reflect.api.JavaUniverse 的子类型时才会发生自动类加载器的魔法,所以如果你转换为 scala.reflect.runtime.JavaUniverse(它继承自 api.JavaUniverse和 internal.SymbolTable),那么你应该没问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-22
  • 1970-01-01
  • 2011-11-28
相关资源
最近更新 更多