TL; DR: Che cosa è reifiedbene per
fun <T> myGenericFun(c: Class<T>)
Nel corpo di una funzione generica come myGenericFun, non è possibile accedere al tipo Tperché è disponibile solo in fase di compilazione ma cancellato in fase di esecuzione. Pertanto, se si desidera utilizzare il tipo generico come classe normale nel corpo della funzione, è necessario passare esplicitamente la classe come parametro, come mostrato in myGenericFun.
Se si crea una inlinefunzione con un reified T , tuttavia, è Tpossibile accedere al tipo di anche in fase di esecuzione e quindi non è necessario passarlo Class<T>ulteriormente. È possibile lavorare con Tcome se fosse una classe normale, ad esempio, si potrebbe voler controllare se una variabile è un esempio di T che si può facilmente fare poi: myVar is T.
Tale inlinefunzione con reifiedtipo ha Til seguente aspetto:
inline fun <reified T> myGenericFun()
Come reifiedfunziona
È possibile utilizzare solo reifiedin combinazione con una inlinefunzione . Tale funzione fa sì che il compilatore copi il bytecode della funzione in ogni luogo in cui la funzione viene utilizzata (la funzione viene "incorporata"). Quando si chiama una funzione inline con tipo reificato, il compilatore conosce il tipo effettivo utilizzato come argomento di tipo e modifica il bytecode generato per utilizzare direttamente la classe corrispondente. Pertanto chiamate come myVar is Tdiventano myVar is String(se l'argomento tipo fosse String) nel bytecode e in fase di esecuzione.
Esempio
Diamo un'occhiata a un esempio che mostra quanto reifiedpossa essere utile . Vogliamo creare una funzione di estensione per la Stringchiamata toKotlinObjectche tenti di convertire una stringa JSON in un semplice oggetto Kotlin con un tipo specificato dal tipo generico della funzione T. Possiamo usare com.fasterxml.jackson.module.kotlinper questo e il primo approccio è il seguente:
a) Primo approccio senza tipo reificato
fun <T> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
//does not compile!
return mapper.readValue(this, T::class.java)
}
Il readValuemetodo prende un tipo che dovrebbe analizzare il JsonObject. Se proviamo a ottenere il Classparametro del tipo T, il compilatore si lamenta: "Impossibile utilizzare 'T' come parametro del tipo reificato. Usa invece una classe."
b) Soluzione alternativa con Classparametro esplicito
fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, c.java)
}
Per ovviare al problema, Classof Tpuò essere impostato come parametro del metodo, che viene quindi utilizzato come argomento per readValue. Funziona ed è un modello comune nel codice Java generico. Può essere chiamato come segue:
data class MyJsonType(val name: String)
val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)
c) La via di Kotlin: reified
L'uso di una inlinefunzione con reifiedparametro type consente Tdi implementare la funzione in modo diverso:
inline fun <reified T: Any> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, T::class.java)
}
Non c'è bisogno di prendere il Classdi in Tpiù, Tpuò essere usato come se fosse una classe normale. Per il client il codice è simile al seguente:
json.toKotlinObject<MyJsonType>()
Nota importante: lavorare con Java
Una funzione incorporata con reifiedtipo non è richiamabile dal codice Java .