Sobes.tech
Middle

Come lavorare con i tipi generici in Kotlin?

sobes.tech AI

Risposta dell'AI

I tipi generici in Kotlin permettono di creare classi, interfacce e funzioni che lavorano con dati di diversi tipi, mantenendo la sicurezza dei tipi durante la compilazione.

Concetti principali e metodi di lavoro:

  • Dichiarazione di classi e interfacce generiche:
    class Box<T>(val item: T) // Classe generica con parametro di tipo T
    interface MyList<E> { // Interfaccia generica con parametro di tipo E
        fun add(element: E)
        fun get(index: Int): E
    }
    
  • Dichiarazione di funzioni generiche:
    fun <T> printAnything(value: T) { // Funzione generica con parametro di tipo T
        println(value)
    }
    
  • Creazione di istanze di tipi generici:
    val intBox: Box<Int> = Box(123) // Specifica di un tipo concreto (Int)
    val stringBox = Box("hello") // Il compilatore deduce il tipo (String)
    
  • Variazioni: Permette di definire come funzionano i sottotipi con tipi generici.
    • Covarianza (out): Permette di usare il tipo e i suoi sottotipi. Si indica con out. Esempio: List<out Any> può contenere List<String>. Usato per tipi che producono valori (ad esempio, lettura da collezioni).
      interface Producer<out T> { // out T - parametro covariante
           fun produce(): T
      }
      
    • Contravarianza (in): Permette di usare il tipo e i suoi supertipi. Si indica con in. Esempio: Comparator<in String> può lavorare con Comparator<Any>. Usato per tipi che consumano valori (ad esempio, scrittura in collezioni).
      interface Consumer<in T> { // in T - parametro contravariante
          fun consume(value: T)
      }
      
    • Invarianza: Il tipo nel parametro generico deve essere esattamente lo stesso. Questo è il comportamento di default.
  • Restrizioni di tipo (where): Permette di limitare il tipo del parametro affinché implementi determinate interfacce o erediti da una classe specifica.
    fun <T : Comparable<T>> max(a: T, b: T): T { // T deve implementare Comparable
        return if (a > b) a else b
    }
    
    fun <T> process(item: T) where T : Runnable, T : Comparable<T> {
        item.run()
        // ... utilizzo della comparabilità
    }
    
  • Proiezione stellare (*): Usata quando non si importa del tipo specifico. Simile a <?> in Java.
    fun printList(list: List<*>) { // Può accettare una lista di qualsiasi tipo
         for (item in list) {
             println(item)
         }
    }
    

I tipi generici in Kotlin usano l'eliminazione dei tipi (type erasure), come in Java. L'informazione sui tipi specifici si perde durante l'esecuzione. Per lavorare con i tipi durante l'esecuzione, si usano tipi reificati.

  • Tipi reificati (reified): Disponibili solo per funzioni inline. Permettono di mantenere l'informazione sul tipo del parametro durante l'esecuzione.
    inline fun <reified T> checkType(value: Any) { // T - tipo reificato
        if (value is T) {
            println("Il valore è del tipo T")
        } else {
            println("Il valore non è del tipo T")
        }
    }