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ò contenereList<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 conComparator<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.
- Covarianza (out): Permette di usare il tipo e i suoi sottotipi. Si indica con
- 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") } }