无法在scala中调用vararg方法

时间:2014-04-05 17:22:15

标签: scala reflection methods invoke variadic-functions

我正在scala中创建一个组合子解析器。解析树由我在评估解析表达式时需要访问的动作组成。其中一个动作(函数)将通过反射在另一个对象上调用一个方法,但是当这是一个vararg方法时会失败。

这是展示问题的代码:

import scala.reflect.runtime.universe._

class M {
  def e: Double = { Math.E }
  def add(x: Double, y: Double): Double = { x + y }
  def sin(x: Double): Double = { Math.sin(x * Math.PI / 180) }
  def max(args: Double*): Double = { args.max }
}

sealed trait Action { def visit: Double }
case class Number(value: Double) extends Action { def visit: Double = value }
case class Function(Name: String, Args: Action*) extends Action {
  def visit: Double = {
    typeOf[M].member(Name: TermName) match {
      case NoSymbol     => throw new Error(s"Unknown function '$Name'")
      case func: Symbol => runtimeMirror(getClass.getClassLoader).reflect(new M).reflectMethod(func.asMethod)(
        (for { arg <- Args } yield arg.visit).toList: _*).asInstanceOf[Double]
    }
  }
}

object Parser {
  def main(args: Array[String]) {
    // Prints 2.718281828459045
    println(Function("e").visit)

    // Prints 7.0
    println(Function("add", Number(3), Number(4)).visit)

    // Prints 1.2246467991473532E-16
    println(Function("sin", Number(180)).visit)

    // Throws IllegalArgumentException: wrong number of arguments
    println(Function("max", Number(1), Number(2.5), Number(50), Number(-3)).visit)
  }
}

任何人都知道如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

这只是一个复制和粘贴解决方案,但我相信你明白了这个想法:

case class VarArgsFunction(Name: String, Args: Action*) extends Action {
  def visit: Double = {
    typeOf[M].member(Name: TermName) match {
      case NoSymbol     => throw new Error(s"Unknown function '$Name'")
      case func: Symbol => {
        runtimeMirror(getClass.getClassLoader).reflect(new M).reflectMethod(func.asMethod)(
          (for { arg <- Args } yield arg.visit).toList).asInstanceOf[Double]
      }
    }
  }
}

object Parser {
  def main(args: Array[String]) {
    // Prints 2.718281828459045
    println(Function("e").visit)

    // Prints 7.0
    println(Function("add", Number(3), Number(4)).visit)

    // Prints 1.2246467991473532E-16
    println(Function("sin", Number(180)).visit)

    // Throws IllegalArgumentException: wrong number of arguments
    println(VarArgsFunction("max", Number(1), Number(2.5), Number(50), Number(-3)).visit)
  }
}