Les déclarations déstructurées


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


Laisser un commentaire

Résoudre : *
25 + 7 =


%d