开发者

Is there any Scala feature that allows you to call a method whose name is stored in a string?

Assuming you开发者_JAVA技巧 have a string containing the name of a method, an object that supports that method and some arguments, is there some language feature that allows you to call that dynamically?

Kind of like Ruby's send parameter.


You can do this with reflection in 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)

And if you want it to be easy in Scala you can make a class that does this for you, plus an implicit for conversion:

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

Doing this sort of thing converts compile-time errors into runtime errors, however (i.e. it essentially circumvents the type system), so use with caution.

(Edit: and see the use of NameTransformer in the link above--adding that will help if you try to use operators.)


Yes. It's called reflection. Here's a link to one way, using some experimental stuff However you should remember that Scala is not a dynamic language, and may not be able to easily do some things that scripting languages can do. You're probably better doing a match on the string, and then calling the right method.


Yes you can! You would need .invoke() method of the method object. Simple example below:

 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 _ => ()}

see code here: https://scastie.scala-lang.org/vasily802/WRsRpgSoSayhHBeAvogieg/9


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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜