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"))

使用すると、 onref.reflectMethod(apply.asMethod)の複数の代替案について不平を言います。調べると、2 つの方法が明らかになります。1 つは署名付きで、もう1 つは. 通話中applyrefapply.asTerm.alternatives(x$1: Int)Int(v1: T1)R

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

(2 番目の選択肢を使用) は、正しい結果 (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 に答える