2016-01-16 13 views
10

Come posso ottenere dinamicamente una funzione per nome in Kotlin?Ottieni dinamicamente la funzione in Kotlin

cioè:

fun myFunc11() { println("Very useful function 11") } 

val funcName = "myFunc" + 11 
val funcRef = getFunction(funcName) 

funcRef() 

Edit: Viene visualizzata la risposta accettata sia corretta, ma il codice è attualmente colpendo alcuni bug in Kotlin. Bug report presentato: https://youtrack.jetbrains.com/issue/KT-10690

+0

Hai considerato di utilizzare i riferimenti alle funzioni invece di chiamare le funzioni per nome? –

+0

Mi piacerebbe acquisire il riferimento alla funzione in modo dinamico. –

risposta

8

Le funzioni globali come fun myFunc11() { ... } definiti nel file denominato cioè Global.kt vengono compilati a static metodi su una classe denominata GlobalKt come descritto in the documentation.

Per ottenere una funzione di riferimento per nome è necessario caricare la classe che la definisce. Se si conosce il nome del file che definisce il riferimento alla funzione che si sta cercando di trovare che si può fare:

fun getFunctionFromFile(fileName: String, funcName: String): KFunction<*>? { 
    val selfRef = ::getFunctionFromFile 
    val currentClass = selfRef.javaMethod!!.declaringClass 
    val classDefiningFunctions = currentClass.classLoader.loadClass("${fileName}Kt") 
    val javaMethod = classDefiningFunctions.methods.find { it.name == funcName && Modifier.isStatic(it.modifiers)} 
    return javaMethod?.kotlinFunction 
} 

Quindi è possibile trovare e chiamare la funzione definita nel file di Global.kt:

fun myFunc11() { println("Very useful function 11") } 

in questo modo:

val kFunction = getFunctionFromFile("Global", "myFunc11") 
kFunction?.call() 

Tuttavia quanto sopra è piuttosto inutile. Una soluzione migliore sarebbe quella di cercare tra tutte le classi disponibili in classpath e con suffisso Kt per raggiungere tutte le funzioni globali. Tuttavia, a causa della natura dei caricatori di classe jvm, questo è un po 'più complicato come descritto in this answer.

+0

Accetto questa risposta in quanto sembra corretta, ma attualmente sto ricevendo un'eccezione: 'kotlin.reflect.KotlinReflectionInternalError: la chiamata non è ancora supportata per questa funzione'. Kotlin 1.0.0-beta-4584 –

+0

@AmirAbiri sembra che tu abbia raggiunto un limite in 'kotlin.reflect' – miensol

+0

Sì, ho generalizzato il caso e inviato un BR. –