2010-01-13 10 views

Odpowiedz

25

Można to zrobić z refleksji w Javie:

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) 

A jeśli ma to być łatwe w Scala można dokonać klasy, która robi to za Ciebie, plus niejawna do konwersji:

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

Tego typu rzeczy przekształcają błędy w czasie kompilacji w błędy środowiska wykonawczego (tzn. W zasadzie omijają system typów), więc należy ich używać z rozwagą.

(Edit. I zobaczyć wykorzystanie NameTransformer w link powyżej - dodając, że pomoże, jeśli spróbujesz użyć operatorów)

+0

Dostaję błąd na poniższych 'List (1, 2) wezwanie ("wziąć", 1)' 'Błąd jest typ. niedopasowanie; znalezione: Int (1) wymagane: AnyRef Uwaga: niejawny istnieje od scala.Int => java.lang.Integer, ale metody odziedziczone z Object są renderowane niejednoznacznie, aby uniknąć niejawnego, który przekształci dowolną scala .Int wszelkich AnyRef.Możesz chcieć użyć typu ascription: x: java.lang.Integer. "Czy istnieje sposób obsługi typów pierwotnych? (Chcę dynamicznie generować listę argumentów ... może być lista 'Dowolny') – dips

+1

@dips - Możesz' .asInstanceOf [AnyRef] 'po drodze (działa również z' Any') lub '1: java.lang.Integer', jak sugeruje błąd, lub możesz dopasować prymitywy i postępuj indywidualnie, jeśli naprawdę tego potrzebujesz, choć nie musisz tego tutaj robić. –

+0

Dzięki! Tak więc mój podpis funkcji 'call' teraz przyjmuje' args: Any * 'i zamieniam go na' AnyRef * 'w ciele' call' jako 'args map {_.asInstanceOf [AnyRef]}'. Mam nadzieję, że to w porządku. Nie znam subtelności, stąd pytanie. – dips

6

Tak. To się nazywa odbicie. Here's a link to one way, using some experimental stuff Należy jednak pamiętać, że Scala nie jest językiem dynamicznym i może nie być w stanie w prosty sposób wykonać pewnych czynności, które mogą wykonywać języki skryptowe. Prawdopodobnie lepiej jest dopasować ciąg, a następnie wywołać odpowiednią metodę.

+0

niedziałający link .... przykro :( –

0
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 
1

Tak można! Będziesz potrzebował metody .invoke() obiektu metody. Prosty przykład poniżej.

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) 
mtd.invoke(hiObj) 
Powiązane problemy