Kotlin est un langage de programmation beaucoup pensé développeur en ce sens ou il propose plusieurs fonctionnalités intéressantes permettant au développeur d’écrire du code avec une syntaxe beaucoup plus claire , courte et concise.
Une fonctionnalité intéressante de kotlin et la déclaration déstructurée qui permet de décomposer un objet en un ensemble de variable
Table des matières
La syntaxe de déclaration déstructurée
Dans kotlin, la déclaration déstructurée est une manière de déclarer plusieurs variables à la fois à partir des valeurs des propriétés d’une instance de classe
Vous pouvez voir la déclaration déstructurée de deux manières:
- Du coté d’une classe, elle permet de décomposer une instance d’une classe en plusieurs variables
- Du coté des variables, elle vous permet dé déclarer plusieurs variables en une seul fois et en une seul ligne de code.
Voici La syntaxe de déclaration déstructurée avec la classe Personne
val personne = Personne("VIGAN","Noé") val (nom,prenom)=personne
En interne la déclaration déstructurée est compilé de la manière suivant.
val nom= personne.component1() val penom = personne.component2()
Les fonctions component()
sont générées par la compilateur soit à partir partir d’une classe marquée avec le mot clé data soit par à partir de la surcharge des opérateurs. Lisez le tutoriel sur la surcharge des opérateurs et sur les classes de données.
Générer les fonction component() avec le mot clé « data » d’une classe
Pour générer les fonction component() pour la classe Personne, vous devez la marquée avec le mot clé data.Vous pouvez utiliser cette méthode si vous avez accès à la modification de la classe ou si c’est une classe que vous avez vous même créer.
Notez que les fonctions component1..N() correspondent à chaque propriété déclarée dans le constructeur primaire de la classe.
Donc pour deux propriétés déclarées dans le constructeur primaire d’une classe il aura les fonctions component1 et component2() , pour trois propriétés il y aura component1(), component2() et component3().
Voici un exemple avec la classe Personne
data class Personne(val nom: String, val prenom: String)
Vous pouvez accéder aux propriétés de cet classe comme suit
val personne = Personne("VIGAN","Noé") val nom= personne.component1() val penom = personne.component2()
Vous pouvez alors utiliser la déclaration déstructurée comme suit
val personne = Personne("VIGAN","Noé") val (nom,prenom)=personne
Définir les fonctions component1..N avec la surcharges des opérateurs
Pour définir les fonctions component1..N(), vous pouvez utiliser la surcharge des opérateurs et définir les fonctions component1..N() directement dans la classe si vous avez accès à la classe ou utiliser les fonctions d’extensions pour ajouter les fonctions component1..N.
Notez que lorsque vous utiliser la surcharges des opérateurs pour définir les fonctions component1..N, vous devez marquer ces fonctions avec le mot clé operator.
Voici un exemple qui montre comment définir les fonctions component1..N() directement dans la classe Personne avec le mot clé data
data class Personne(val nom: String, val prenom: String) fun main(){ val personne = Personne("VIGAN","Noé") val (nom,prenom)=personne }
Dans cette exemple la classe Personne est marqué avec le mot clé data pour générer les fonctions component
Voici un exemple qui montre comment définir les fonctions component1..N() sans utilisé le mot clé data.
class Personne(val nom: String, val prenom: String){ operator fun component1(): String = nom operator fun component2(): String = prenom } fun main(){ val personne = Personne("VIGAN","Noé") val (nom,prenom)=personne }
Vous pouvez aussi déclarer ces fonctions component1..N() avec les extensions de fonction comme suit
class Personne(val nom: String, val prenom: String) operator fun Personne.component1(): String = this.nom operator fun Personne.component2(): String = this.prenom fun main(){ val personne = Personne("VIGAN","Noé") val (nom,prenom)=personne }
La déclaration déstructurée avec les collections et la boucles for
Il est aussi possible de parcourir les éléments d’une collection avec la déclaration déstructurée comme suit.
class Personne(val nom: String, val prenom: String) operator fun Personne.component1(): String = this.nom operator fun Personne.component2(): String = this.prenom fun main(){ val listPersonne = listOf(Personne("Musk","Elon"), Personne("Torvalds","Linux")) for((nom,prenom) in listPersonne){ println("$nom, $prenom ") } }
Résultat:
Musk, Elon
Torvalds, Linux
Type de retour d’une fonction et la déclaration déstructurée
Vous pouvez récupérer le résultat d’une fonction qui retourne deux valeurs dans deux variables avec la déclaration déstructurée.
Déclarerez d’abord une classe Result marquée avec le mot clé data qui représentera le type de retour d’une fonction
data class Response(val message: String, val statut: Int)
Ensuite créez une fonction qui retourne une instance de la classe Result comme suit.
fun getResponse():Response{ val result =Response("Messeage réçu",200) return result }
Vous pouvez ensuite appeler cette fonction et créer deux variables à qui vous assignez le résultat de la fonction précédent avec la déclaration déstructurée comme suit
fun main(){ val (message,statut) = getResponse() println("$statut, $message") }
La déclaration déstructurés et les tables de hachage
On peut parcourir les différents éléments d’une table de hachage avec la déclaration déstructuré comme suit.
fun main(){ val numberMap= mapOf("key1" to 1, "key2" to 2) for ((key,value) in numberMap){ println("la valeur $value a pour clé $key") } }
Cela est possible parce que dans les librairies standard de kotlin, sont définies des fonctions component1..N() d’extension pour parcourir et récupérer la clé et la valeur de chaque élément de la table de hachage.
Voici les fonctions déjà implémentées dans les librairies standard de kotlin
operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = entrySet().iterator() operator fun <K, V> Map.Entry<K, V>.component1() = getKey() operator fun <K, V> Map.Entry<K, V>.component2() = getValue()
Underscore et les variables déstructurées depuis kotlin 1.1
Si vous n’avez pas besoin d’une variable dans une déclaration déstructurée, vous pouvez remplacer le nom d’un variable par un underscore.
Pour bien comprendre l’utilisé des underscore, il faut bien comprendre comment kotlin déstructure une classe ou le type de retour d’une fonction en un ensemble de variable.
Par exemple lorsque vous avez un classe Personne avec trois propriétés nom,prenom age déclarées dans le constructeur primaire comme suit
data class Personne(val nom: String, val prenom: String, val age: Int)
Si vous souhaitez uniquement récupérer le prenom et l’age , kotlin vous enverra toujours les deux premiers éléments dont le nom et le prénom comme suit
data class Personne(val nom: String, val prenom: String, val age: Int) fun main(){ val personne = Personne("Ruck","Rose",12) val (prenom,age)= personne println("$prenom, $age") }
Résultat: Ruck, Rose
Kotlin renvoie toujours les valeurs des propriétés dans leur ordre de déclaration dans le constructeur primaire car il appelle les fonctions component1..N() dans l’ordre d1… à N correspondant à l’ordre de déclaration des propriétés du constructeur primaire.
ce qui fait que c’est la valeur des propriété nom et prenom qui est envoyé
Le underscore peut vous permet de demander à kotlin de ne pas appeler la fonction componentN() partout où vous avez remplacé le underscore par un nom de variable
Donc avec l’exemple de la classe Personne précédente, vous pouvez sauter la propriété nom ,ensuite récupérer uniquement le prenom et l’age et remplacé la variable représentant le nom par underscope avec la déclaration déstructuré, comme suit.
val personne = Personne("Ruck","Rose",12) val (_,prenom,age)= personne println("$prenom, $age")
Résultat: Rose, 12
La déstructuration avec les expressions lambda depuis kotlin 1.1
Vous pouvez utiliser la syntaxe de déclarations déstructurée avec les paramètres d’une expression lambda.
Si une expression lambda à un paramètre de type Pair
ou de type Map.Entry qui ont des fonctions component approprié, vous pouvez utiliser plusieurs paramètres pour représenter cette pair au lieu d’un seul paramètre.
map.mapValues { entry -> "${entry.value}!" } map.mapValues { (key, value) -> "$value!" }
Vous devez aussi faire la différence entre déclarer deux paramètres d’une expression lambda et déclarer une pair déstructurée au lieur d’un paramètre
{ a -> ... } // Un paramètre { a, b -> ... } // Duex paramètres { (a, b) -> ... } // Une paire déstructurée { (a, b), c -> ... } // Une paire déstructurée et un autre paramètre
SI un composant des paramètres déstructurés est inutilisable, vous pouvez le remplacer par un underscore pour éviter d’inventer un nom.Voir l’exemple
map.mapValues { (_, value) -> "$value!" }
Vous pouvez spécifier le type de l’ensemble des paramètres déstructurées ou spécifié le type d’un composant des paramètres déstructurées
map.mapValues { (_, value): Map.Entry<Int, String> -> "$value!" } map.mapValues { (_, value: String) -> "$value!" }
Conclusion
Voila,nous sommes à la fin de ce tutoriel sur la déclaration déstructuré.J’espère que ce tutoriel vous aidera.A bientôt pour un nouveau tutoriel.
Autres ressources
https://kotlinlang.org/docs/reference/multi-declarations.html
Noe Joel Vigan, auteur de ce blog, est passionné par la programmation Android. Il a créé ce blog pour partager ses connaissances sur le développement d’application android. Il est Développeur Android Fullstack, ce qui lui permet de complètement mettre en place le Backend de ses applications sur Google Cloud à défaut d’utiliser FireBase.