extension function — un meccanismo di Kotlin che consente di aggiungere nuovi metodi a classi esistenti senza ereditarietà e senza modificare il codice sorgente. La funzione viene dichiarata con un prefisso sotto forma di tipo ricevente e viene chiamata come un metodo normale di quel tipo. Secondo Kotlin Documentation, 2025, le extension functions vengono compilate in metodi statici con il ricevente come primo parametro, garantendo zero overhead in fase di esecuzione rispetto alle chiamate normali.
Punti chiave
Una extension function è una funzione dichiarata all'esterno di una classe ma chiamata come suo metodo. Prende un tipo ricevente a cui viene aggiunto il nuovo metodo. All'interno della funzione, la parola chiave this si riferisce all'istanza del tipo ricevente. Questo approccio consente di estendere classi finali, classi di librerie di terze parti e persino tipi primitivi senza creare wrapper.
A differenza di Java, dove aggiungere un metodo a una classe esistente richiede l'ereditarietà o una classe di utilità statica, Kotlin offre una soluzione elegante senza boilerplate. Secondo uno studio della Kotlin Foundation (2024), le extension functions sono tra le cinque funzionalità più utilizzate del linguaggio — il 78% degli sviluppatori Kotlin le usa nel lavoro quotidiano.
Il compilatore Kotlin traduce una extension function in un metodo statico in cui l'istanza del ricevente viene passata come primo argomento. Ciò significa che le extension functions non modificano il bytecode della classe di destinazione e non violano l'incapsulamento — solo i campi e i metodi pubblici del ricevente sono accessibili.
Utilizza le extension functions per scrivere funzioni di utilità pulite che sono logicamente legate a un tipo specifico ma non possono essere aggiunte al suo codice sorgente.
La sintassi di base di una extension function: il nome del tipo ricevente, un punto, il nome della funzione, poi i parametri e il tipo di ritorno. All'interno della funzione, il ricevente è accessibile tramite this.
// Extension function for String
fun String.isEmail(): Boolean {
return this.contains("@") && this.contains(".")
}
// Called as regular String method
val result = "user@example.com".isEmail() // true
In questo esempio, isEmail() diventa disponibile per tutte le stringhe. All'interno della funzione, this si riferisce alla stringa stessa su cui viene chiamato il metodo. Kotlin consente di omettere this nella maggior parte dei casi — si può scrivere semplicemente contains("@") invece di this.contains("@").
Le extension functions possono accettare parametri aggiuntivi e restituire valori di qualsiasi tipo. Questo le rende funzioni a tutti gli effetti, non solo zucchero sintattico.
fun List<Int>.defaultIfEmpty(default: Int): List<Int> {
if (this.isEmpty()) return listOf(default)
return this
}
val populated = listOf(1, 2).defaultIfEmpty(0)
val empty = listOf<Int>().defaultIfEmpty(0)
Il parametro default definisce il valore restituito per una lista vuota. Una extension function può essere generica — il tipo List
Le extension functions in Kotlin utilizzano il dispatch statico, non il dispatch virtuale. Questa è una differenza fondamentale rispetto ai metodi di classe normali. Quale extension function verrà chiamata è determinato in fase di compilazione dal tipo statico della variabile, non dal suo tipo effettivo in fase di esecuzione.
open class Animal
class Dog : Animal()
fun Animal.speak() = "Animal sound"
fun Dog.speak() = "Woof"
fun test() {
val animal: Animal = Dog()
println(animal.speak()) // "Animal sound" — static type Animal
val dog: Dog = Dog()
println(dog.speak()) // "Woof" — static type Dog
}
Anche se la variabile animal punta a un'istanza di Dog, viene chiamata l'extension function per Animal perché il tipo statico della variabile è Animal. Se speak() fosse un metodo virtuale di classe, verrebbe chiamato Dog.speak(). Questo comportamento è importante da considerare quando si progettano API con extension functions.
Le extension functions non sono membri della classe — sono funzioni normali che richiedono un import per essere utilizzate in un altro file. Kotlin fornisce due opzioni di import: per nome della funzione o con rinominazione.
// Import by name
import com.example.extensions.isEmail
// Import with alias (to resolve conflicts)
import com.example.extensions.isEmail as isValidEmail
// Call after import
val valid = "test@test.com".isEmail()
La rinominazione tramite as è utile per conflitti di nomi — ad esempio, se due librerie forniscono una extension function con lo stesso nome per lo stesso tipo. In questo caso, è possibile importarne una con un nome diverso e chiamarla usando il nuovo nome.
Le extension functions possono essere dichiarate a diversi livelli:
| Livello | Visibilità | Esempio |
|---|---|---|
| Top-level | Intero progetto dopo l'import | fun String.isEmail() |
| Member extension | All'interno della classe proprietaria | class A { fun B.ext() } |
| Local | All'interno di una funzione | fun test() { fun String.ext() } |
Le member extension functions sono un caso speciale in cui una extension function viene dichiarata all'interno di un'altra classe. In questo caso, sia il ricevente (this della funzione) che i membri della classe esterna sono accessibili all'interno dell'extension function.
Se una classe ha un metodo con la stessa firma di una extension function, viene sempre chiamato il membro della classe. Una extension function non sovrascrive mai un metodo di classe — questa è una decisione architetturale per prevenire sovrascritture accidentali.
class User {
fun greet() = "Hello from class"
}
fun User.greet() = "Hello from extension"
fun main() {
val user = User()
println(user.greet()) // "Hello from class"
}
Anche se l'extension function viene definita successivamente e ha la stessa firma, il compilatore sceglierà il metodo della classe. Il compilatore Kotlin emette un avviso quando rileva questa situazione. L'unico modo per chiamare l'extension function quando esiste un metodo di classe è invocarla come funzione normale: greet(user).
Nello sviluppo Android, le extension functions sono diventate uno strumento standard per lavorare con View, Context e fragment. La libreria Android KTX è costruita sulle extension functions, fornendo wrapper convenienti sull'API Android.
// Extension function for working with View
fun View.show() {
visibility = View.VISIBLE
}
fun View.hide() {
visibility = View.GONE
}
// Extension function for Context — toast
fun Context.toast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
// Extension function as DSL builder
fun String.colorFormat(color: String): String =
"$color$this\u001b[0m"
L'extension function toast() rende concisi i chiamate dipendenti da Context: invece di scrivere Toast.makeText(context, message, length).show(), basta scrivere context.toast("Testo"). Questo riduce il boilerplate e rende il codice più leggibile.
Domande frequenti
No, le extension functions utilizzano il dispatch statico. Se dichiari una extension function per una classe base e la stessa per una sottoclasse, quale verrà chiamata è determinata dal tipo statico della variabile in fase di compilazione, non dal tipo effettivo in fase di esecuzione.
Puoi dichiarare extension functions per tipi riceventi nullable: fun String?.isNullOrEmail(). All'interno di tale funzione, this può essere null, quindi devi utilizzare operatori di chiamata sicura o controlli espliciti di null.
No, le extension functions vengono compilate come metodi statici. A livello di bytecode, chiamare una extension function è identico a chiamare un metodo statico con il ricevente come primo parametro. Nessuna riflessione o dispatch dinamico è coinvolto.
Sì, le extension properties funzionano in modo simile alle extension functions ma non possono memorizzare stato — solo un getter e un setter. Ad esempio: val List
In Java si scrive StringUtils.isEmail(str), mentre in Kotlin si scrive str.isEmail(). La differenza non è solo sintattica: le extension functions supportano l'autocompletamento nell'IDE, migliorano la leggibilità delle catene di chiamate e consentono all'IDE di suggerire funzioni pertinenti per un tipo specifico. Java non ha queste capacità.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche