假设你有一个包含方法名称的字符串,一个支持该方法和一些参数的对象,是否有一些语言功能允许你动态调用它?
有点像Ruby的send
参数。
答案 0 :(得分:30)
您可以使用Java中的反射执行此操作:
class A {
def cat(s1: String, s2: String) = s1 + " " + s2
}
val a = new A
val hi = "Hello"
val all = "World"
val method = a.getClass.getMethod("cat",hi.getClass,all.getClass)
method.invoke(a,hi,all)
如果你希望它在Scala中变得简单,你可以创建一个为你做这个的类,加上隐含的转换:
case class Caller[T>:Null<:AnyRef](klass:T) {
def call(methodName:String,args:AnyRef*):AnyRef = {
def argtypes = args.map(_.getClass)
def method = klass.getClass.getMethod(methodName, argtypes: _*)
method.invoke(klass,args: _*)
}
}
implicit def anyref2callable[T>:Null<:AnyRef](klass:T):Caller[T] = new Caller(klass)
a call ("cat","Hi","there")
执行此类操作会将编译时错误转换为运行时错误(但它基本上会绕过类型系统),因此请谨慎使用。
(编辑:并在上面的链接中查看NameTransformer的使用 - 如果您尝试使用运算符,这将有所帮助。)
答案 1 :(得分:6)
是。它被称为反射。 Here's a link to one way, using some experimental stuff但是您应该记住,Scala不是动态语言,可能无法轻松完成脚本语言可以执行的操作。你可能最好在字符串上进行匹配,然后调用正确的方法。
答案 2 :(得分:2)
是的,你可以!
您需要方法对象的.invoke()
方法。以下简单示例:
import scala.util.Try
case class MyCaseClass(i: String) {
def sayHi = {
println(i)
}
}
val hiObj = MyCaseClass("hi")
val mtdName = "sayHi"
// Method itself as an object
val mtd = hiObj.getClass.getMethod(mtdName)
Try {mtd.invoke(hiObj)}.recover { case _ => ()}
请在此处查看代码:https://scastie.scala-lang.org/vasily802/WRsRpgSoSayhHBeAvogieg/9
答案 3 :(得分:1)
scala> val commandExecutor = Map("cleanup" -> {()=> println("cleanup successfully")} )
commandExecutor: scala.collection.immutable.Map[String,() => Unit] = Map(cleanup -> <function0>)
scala> val command="cleanup"
command: String = cleanup
scala> commandExecutor(command).apply
cleanup successfully