2

我正在尝试使用 v2.11.6 中的 scala 反射 api 调用一个函数:

import scala.reflect.runtime.{universe => ru}

def f(i: Int) = i + 2

val fn: Any = (f _)
val ref = ru.runtimeMirror(ru.getClass.getClassLoader).reflect(fn)
val apply = ref.symbol.typeSignature.member(ru.TermName("apply"))

使用ref.reflectMethod(apply.asMethod)它时会抱怨applyon 的多种替代方案ref。检查apply.asTerm.alternatives揭示了两种方法,一种使用签名(x$1: Int)Int,另一种使用(v1: T1)R. 打电话

ref.reflectMethod(apply.asTerm.alternatives(1).asInstanceOf[ru.MethodSymbol])(1)

(使用第二种选择)返回正确的结果 (3)。但是调用第一个替代方案会引发异常:java.lang.IllegalArgumentException: object is not an instance of declaring class

这些替代方案是什么,我如何确保始终调用正确的替代方案?使用此方法调用 Function2 或更高版本似乎也存在问题,那么正确的方法是什么?

4

1 回答 1

3

有重载apply方法的原因Function1@specialized为了原始类型。

我不知道是否有更好的方法来区分它们,但以下方法似乎有效,寻找其参数擦除的替代方案AnyRef(而不是诸如 的原语Int):

def invoke(fun1: Any, arg1: Any): Any = {
  import scala.reflect.runtime.{universe => ru}
  val mirror  = ru.runtimeMirror(ru.getClass.getClassLoader)
  val ref     = mirror.reflect(fn)
  val applies = ref.symbol.typeSignature.member(ru.TermName("apply"))
  val syms    = apply.alternatives.map(_.asMethod)  
  val sym     = syms.find { m =>
    m.paramLists match {
      case (arg :: Nil) :: Nil 
        if arg.asTerm.typeSignature.erasure =:= ru.typeOf[AnyRef] => true
      case _ => false
    }
  } getOrElse sys.error("No generic apply method found")
  ref.reflectMethod(sym)(arg1)
}

// Test:
val fn: Any = (i: Int) => i + 2
invoke(fn, 1)  // res: 3
于 2015-08-13T13:38:56.187 回答