Есть ли функция Scala, которая позволяет вам вызвать метод, имя которого хранится в строке?
Предполагая, что у вас есть строка, содержащая имя метода, объект, который поддерживает этот метод и некоторые аргументы, есть ли какая-то языковая функция, которая позволяет вам динамически ее называть?
Вид вроде параметра Ruby send
.
Ответы
Ответ 1
Вы можете сделать это с отражением в 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 в приведенной выше ссылке - добавление, которое поможет, если вы попытаетесь использовать операторов.)
Ответ 2
Да. Это называется отражением. Здесь ссылка на один способ, используя некоторые экспериментальные материалы Однако вы должны помнить, что Scala не является динамическим языком и может оказаться невозможным легко выполнять некоторые действия, которые могут выполнять языки сценариев. Вероятно, вам лучше сделать совпадение в строке, а затем вызвать правильный метод.
Ответ 3
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
Ответ 4
Да, ты можешь! Вам потребуется .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