Sobes.tech
Middle

Comment travailler avec les types génériques en Kotlin?

sobes.tech IA

Réponse de l'IA

Les types génériques en Kotlin permettent de créer des classes, interfaces et fonctions qui manipulent des données de différents types tout en assurant la sécurité de type lors de la compilation.

Concepts clés et méthodes de travail :

  • Déclaration de classes et interfaces génériques :
    class Box<T>(val item: T) // Classe générique avec paramètre de type T
    interface MyList<E> { // Interface générique avec paramètre de type E
        fun add(element: E)
        fun get(index: Int): E
    }
    
  • Déclaration de fonctions génériques :
    fun <T> printAnything(value: T) { // Fonction générique avec paramètre de type T
        println(value)
    }
    
  • Création d'instances de types génériques :
    val intBox: Box<Int> = Box(123) // Spécification d'un type concret (Int)
    val stringBox = Box("hello") // Le compilateur infère le type (String)
    
  • Variantes : Permet de définir comment fonctionnent les sous-types avec des types génériques.
    • Covariance (out) : Permet d'utiliser le type et ses sous-types. Indiqué par out. Exemple : List<out Any> peut contenir List<String>. Utilisé pour les types qui produisent des valeurs (par exemple, lecture de collections).
      interface Producer<out T> { // out T - paramètre covariant
           fun produce(): T
      }
      
    • Contravariance (in) : Permet d'utiliser le type et ses super-types. Indiqué par in. Exemple : Comparator<in String> peut fonctionner avec Comparator<Any>. Utilisé pour les types qui consomment des valeurs (par exemple, écriture dans une collection).
      interface Consumer<in T> { // in T - paramètre contravariant
          fun consume(value: T)
      }
      
    • Invariance : Le type dans le paramètre générique doit être exactement le même. C'est le comportement par défaut.
  • Restrictions de types (where) : Permet de limiter le type du paramètre pour qu'il implémente certaines interfaces ou hérite d'une classe spécifique.
    fun <T : Comparable<T>> max(a: T, b: T): T { // T doit implémenter Comparable
        return if (a > b) a else b
    }
    
    fun <T> process(item: T) where T : Runnable, T : Comparable<T> {
        item.run()
        // ... utilisation de la comparabilité
    }
    
  • Projection étoile (*) : Utilisée lorsque l'on ne se soucie pas des arguments spécifiques du type. Semblable à <?> en Java.
    fun printList(list: List<*>) { // Peut accepter une liste de n'importe quel type
         for (item in list) {
             println(item)
         }
    }
    

Les types génériques en Kotlin utilisent l'effacement de type (type erasure), comme en Java. L'information sur les types spécifiques est perdue en temps d'exécution. Pour travailler avec des types en temps d'exécution, on utilise des types reifiés.

  • Types reifiés (reified) : Disponibles uniquement pour les fonctions inline. Permettent de conserver l'information du type du paramètre en temps d'exécution.
    inline fun <reified T> checkType(value: Any) { // T - type reifié
        if (value is T) {
            println("Le valeur est du type T")
        } else {
            println("Le valeur n'est pas du type T")
        }
    }