我正在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)
}
}
任何人都知道如何解决这个问题?
答案 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)
}
}