2010-01-13 8 views

risposta

25

È possibile farlo con la riflessione 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) 

E se si vuole che sia facile a Scala si può fare una classe che fa per voi, oltre a un implicito per la conversione:

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

Fare questo genere di cose converte gli errori in fase di compilazione in errori di runtime, tuttavia (vale a dire essenzialmente aggira il sistema di tipi), quindi usare con cautela.

(Edit:. E vedere l'uso della NameTransformer nel link qui sopra - aggiungendo che vi aiuterà se si tenta di utilizzare gli operatori)

+0

sto errore di salire sul seguente 'List (1, 2) chiamata ("prendere", 1)' 'L'errore è di tipo. mismatch; found: Int (1) richiesto: AnyRef Nota: esiste un implicito da scala.Int => java.lang.Integer, ma i metodi ereditati da Object sono resi ambigui. Questo per evitare impliciti di copertina che convertono in qualsiasi scala .Int a qualsiasi AnyRef. Potresti voler usare un attributo di tipo: x: java.lang.Integer. C'è un modo per gestire i tipi primitivi? (Voglio generare dinamicamente l'elenco degli argomenti ... potrebbe essere una lista di 'Any') – dips

+1

@dips - Puoi' .asInstanceOf [AnyRef] 'per la via in (funziona anche con' Any'), o '1: java.lang.Integer' come suggerisce l'errore. Oppure puoi abbinare le primitive e gestisci caso per caso se davvero ne hai bisogno, anche se non dovresti aver bisogno di qui. –

+0

Grazie! Quindi la firma della funzione 'call' ora richiede' args: Any * 'e lo converto in' AnyRef * 'nel corpo di' call' come 'args map {_.asInstanceOf [AnyRef]}'. Spero che vada bene. Non so le sottigliezze, quindi chiedendo. – dips

6

Sì. Si chiama riflessione. Here's a link to one way, using some experimental stuff Tuttavia dovresti ricordare che Scala non è un linguaggio dinamico e potrebbe non essere in grado di fare facilmente alcune cose che i linguaggi di scripting possono fare. Probabilmente stai meglio facendo una corrispondenza sulla stringa e poi chiamando il metodo giusto.

+0

collegamento rotto .... scusate :( –

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

Sì, è possibile! È necessario il metodo .invoke() dell'oggetto metodo. Semplice esempio che segue:.

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) 
Problemi correlati