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

后端 未结 4 1269
刺人心
刺人心 2020-12-05 03:20

Assuming you 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 th

相关标签:
4条回答
  • 2020-12-05 03:26

    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

    0 讨论(0)
  • 2020-12-05 03:29

    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.

    0 讨论(0)
  • 2020-12-05 03:50
    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 讨论(0)
  • 2020-12-05 03:52

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

    0 讨论(0)
提交回复
热议问题