web-dev-qa-db-fra.com

Comment fonctionne le mot clé réifié dans Kotlin?

J'essaie de comprendre le but du mot clé reified, apparemment cela nous permet de faire une réflexion sur les génériques .

Cependant, lorsque je le laisse de côté, cela fonctionne aussi bien. Quelqu'un veut-il expliquer quand cela fait une différence réelle ?

87
hl3mukkel

TL; DR: Qu'est-ce que reified convient?

_fun <T> myGenericFun(c: Class<T>) 
_

Dans le corps d'une fonction générique telle que myGenericFun, vous ne pouvez pas accéder au type T car il est uniquement disponible au moment de la compilation mais effacé au moment de l'exécution. Par conséquent, si vous souhaitez utiliser le type générique en tant que classe normale dans le corps de la fonction, vous devez explicitement transmettre la classe en tant que paramètre , comme indiqué dans myGenericFun.

Si vous créez une fonction inline avec un reifié T, le type de T est accessible même à l'exécution et vous n'avez donc pas besoin de passer le _Class<T>_ en plus. Vous pouvez utiliser T comme s'il s'agissait d'une classe normale, par exemple. vous voudrez peut-être vérifier si une variable est une instance de T, ce que vous pouvez facilement faire ensuite: _myVar is T_.

Une telle fonction inline avec reified de type T se présente comme suit:

_inline fun <reified T> myGenericFun()
_

Comment fonctionne reified

Vous pouvez uniquement utiliser reified en combinaison avec une fonction inline . Une telle fonction oblige le compilateur à copier le bytecode de la fonction à chaque endroit où la fonction est utilisée (la fonction est "en ligne"). Lorsque vous appelez une fonction en ligne de type réifié, le compilateur connaît le type utilisé en tant qu'argument de type et modifie le bytecode généré pour utiliser directement la classe correspondante. Par conséquent, des appels tels que _myVar is T_ deviennent _myVar is String_ (si l'argument de type était String) dans le bytecode et au moment de l'exécution.


Exemple

Voyons un exemple qui montre à quel point reified peut être utile. Nous voulons créer une fonction d'extension pour String appelée toKotlinObject qui tente de convertir une chaîne JSON en un objet Kotlin brut avec un type spécifié par le type générique de la fonction T. Nous pouvons utiliser com.fasterxml.jackson.module.kotlin pour cela et la première approche est la suivante:

a) Première approche sans type réifié

_fun <T> String.toKotlinObject(): T {
      val mapper = jacksonObjectMapper()
                                                        //does not compile!
      return mapper.readValue(this, T::class.Java)
}
_

La méthode readValue prend un type qu’elle est supposée analyser le JsonObject. Si nous essayons d'obtenir le Class du paramètre de type T, le compilateur se plaint: "Impossible d'utiliser 'T' comme paramètre de type réifié. Utilisez plutôt une classe."

b) Solution de contournement avec le paramètre explicite Class

_fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
    val mapper = jacksonObjectMapper()
    return mapper.readValue(this, c.Java)
}
_

En guise de solution de contournement, le Class de T peut être transformé en paramètre de méthode, qui sera ensuite utilisé comme argument de readValue. Cela fonctionne et est un modèle commun dans le code générique Java. On peut l'appeler comme suit:

_data class MyJsonType(val name: String)

val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)
_

c) La méthode Kotlin: reified

L'utilisation d'une fonction inline avec reified est un paramètre de type T qui permet d'implémenter la fonction différemment:

_inline fun <reified T: Any> String.toKotlinObject(): T {
    val mapper = jacksonObjectMapper()
    return mapper.readValue(this, T::class.Java)
}
_

Il n’est pas nécessaire de prendre le Class de T de plus, T peut être utilisé comme s’il s’agissait d’une classe ordinaire. Pour le client, le code ressemble à ceci:

_json.toKotlinObject<MyJsonType>()
_

Remarque importante: Travailler avec Java

Une fonction en ligne de type reified est non appelable à partir de code Java .

249
s1m0nw1