ProgrammazioneSviluppatore Android

Spiega la differenza tra parametri generici normali, inline e reified in Kotlin. Quando e perché si usa reified, quali vincoli standard del metodo generico rimuove?

Supera i colloqui con l'assistente IA Hintsage

Risposta

In Kotlin i generici (parametri generici) per impostazione predefinita sono soggetti a "type erasure": durante l'esecuzione non ci sono informazioni sui tipi. Questo complica la riflessione, la conversione dei tipi e la lettura delle annotazioni per tipo. Per la maggior parte dei compiti, questo è accettabile: i generici normali funzionano in modo simile a Java.

Le funzioni inline con il parametro reified consentono di "forzare" il compilatore a "sostituire" un tipo specifico nel punto di chiamata, permettendo alla funzione di eseguire operazioni con il tipo a tempo di esecuzione (ad esempio, effettuare controlli, creare nuove istanze tramite riflessione, ecc.). Tuttavia, reified può essere applicato solo a parametri in funzioni inline.

Esempio di confronto:

// Generic normale fun <T> printType(t: T) { println(t.javaClass) // Genererà ClassCastException per List<Int> e altro. } // con reified inline fun <reified T> printType(t: T) { println(T::class.simpleName) } fun main() { printType(123) // Stampa: Int printType("hello") // Stampa: String }

Pratica di applicazione: Viene utilizzato principalmente per controllare il tipo, il casting, la riflessione, la creazione di istanze, dove non è possibile ottenere il tipo in altro modo.

Domanda trabocchetto

"Può una funzione con tipo reified non essere inline?"

  • No — reified funziona solo nelle funzioni inline. Altrimenti, non è possibile sostituire il tipo durante la compilazione.

Esempio di utilizzo errato:

fun <reified T> failFunction() {} // Errore di compilazione: il parametro di tipo reified può essere utilizzato solo su una funzione inline

Corretto:

inline fun <reified T> goodFunction() {}

Esempi di errori reali a causa della mancanza di conoscenza delle sottigliezze dell'argomento


Storia

In un progetto era necessario analizzare universalmente le stringhe JSON in qualsiasi tipo tramite una funzione con un parametro generico. L'implementazione standard tramite fun <T> parse(json: String): T non funzionava correttamente a causa della type erasure — non era possibile ottenere Class<T> per analizzare collezioni e modelli generici. Abbiamo risolto tramite inline con tipo reified — il problema è scomparso.


Storia

Uno degli sviluppatori cercava di creare istanze del tipo T utilizzando un costruttore normale T(), senza usare inline e reified. Durante la compilazione si è verificato un errore, poiché le informazioni sul tipo erano state cancellate. Riscrivendo in inline fun <reified T: Any> siamo riusciti a risolvere tutto con i mezzi standard del linguaggio.


Storia

Tentando di utilizzare reified in una normale funzione (senza inline) — l'IDE ha restituito un errore di compilazione fuorviante. Lo sviluppatore ha cercato a lungo la causa, fino a quando non ha studiato la documentazione e ha corretto la funzione, aggiungendo inline.