Scope functions în Kotlin sunt cinci funcții ale bibliotecii standard (let, run, with, apply, also), care execută un bloc de cod în contextul unui obiect. Ele diferă prin modul de acces la obiect (prin it sau this) și prin valoarea returnată (obiectul contextual sau rezultatul lambdei). Conform documentației Kotlin (2026), alegerea corectă a scope function reduce codul boilerplate cu 25–40%. Scope functions ajută la scrierea inițializării, configurării și transformării obiectelor în stil declarativ.
Puncte principale
Scope functions (funcții de domeniu) — este un set de cinci funcții (let, run, with, apply, also) încorporate în biblioteca standard Kotlin. Fiecare dintre ele primește o lambdă și modifică temporar domeniul de vizibilitate astfel încât în interiorul lambdei codul se execută în contextul unui obiect specific. Acest lucru evită repetarea numelui obiectului la apeluri multiple și grupează operațiile conexe într-un singur bloc.
Două caracteristici cheie deosebesc scope functions: modul de acces la obiectul contextual (prin this sau prin it) și valoarea returnată (obiectul contextual însuși sau rezultatul lambdei). Accesul prin this face obiectul destinatar implicit — metodele și proprietățile sunt apelate fără prefix. Accesul prin it transmite obiectul ca parametru explicit al lambdei. Returnarea obiectului permite construirea de lanțuri, returnarea rezultatului — atribuirea valorii transformate.
Istoric, scope functions au apărut ca înlocuitor al modelului clasic Builder și al variabilelor temporare pentru inițializare. În loc să se creeze o clasă builder separată, programatorul scrie apply { proprietate1 = ...; proprietate2 = ... }. Aceasta reduce cantitatea de cod și face inițializarea mai lizibilă. În ecosistemul Kotlin, scope functions sunt utilizate în toate framework-urile și bibliotecile ca idiom standard al limbajului.
Alegerea scope function potrivite este determinată de două întrebări: doriți să utilizați this sau it pentru accesul la obiect și doriți să returnați obiectul însuși sau rezultatul lambdei. Combinația a două caracteristici binare oferă patru variante posibile, iar with ocupă un loc special ca singura funcție care nu este o extensie.
| Funcția | Acces | Returnare | Extensie? | Scenariu tipic |
|---|---|---|---|---|
| let | it | rezultatul lambdei | da | Transformare, verificare null |
| run | this | rezultatul lambdei | da | Calcul cu context |
| with | this | rezultatul lambdei | nu | Gruparea apelurilor |
| apply | this | obiectul contextual | da | Inițializarea proprietăților |
| also | it | obiectul contextual | da | Efecte secundare, logare |
Pentru configurarea obiectului fără returnarea unei noi valori utilizați apply (acces prin this) sau also (acces prin it). Pentru calcularea unei noi valori pe baza obiectului utilizați let (acces prin it) sau run (acces prin this). Pentru gruparea apelurilor fără înlănțuire utilizați with. Respectarea acestei scheme face codul predictibil pentru alți dezvoltatori familiarizați cu Kotlin.
apply — scope function care returnează obiectul contextual și oferă acces la acesta prin this. Este instrumentul ideal pentru inițializarea proprietăților obiectului după creare. În interiorul blocului apply se pot seta proprietăți fără repetarea numelui obiectului. Metoda returnează obiectul însuși, ceea ce permite încorporarea apply în lanțuri sau utilizarea în inițializatori.
data class ServerConfig(
var host: String = "localhost",
var port: Int = 8080,
var useTls: Boolean = false
)
val config = ServerConfig().apply {
host = "api.example.com"
port = 443
useTls = true
}
În listare, apply configurează ServerConfig, accesând proprietățile direct prin this (this omis). Fără apply ar trebui să scrieți config.host = ..., config.port = ... — trei referințe repetate la aceeași variabilă. Returnarea obiectului permite salvarea rezultatului configurării în val config. also, spre deosebire de apply, transmite obiectul prin it și este potrivit pentru efecte secundare.
fun saveUser(user: User) {
validate(user).also { result ->
println("Rezultatul validării: $result")
}
val savedUser = user.also {
log("Saving user ${it.id}")
database.save(it)
}
}
În exemplu, also este utilizat pentru logare — returnând obiectul original, execută o acțiune secundară (afișarea unui mesaj) fără a modifica obiectul. Acesta este un lanț: validate(user) returnează User, also loghează rezultatul și transmite utilizatorul mai departe. also este util și pentru adăugarea elementelor în colecții sau depanarea în mijlocul unui lanț de transformări.
let — scope function care returnează rezultatul lambdei și transmite contextul prin it. Este funcția principală pentru transformări sigure la null: dacă obiectul este nullable, combinația ?.let { } va executa blocul doar la valoare non-null. let este utilizat și pentru limitarea domeniului de vizibilitate al variabilelor temporare și transformări de tip map de la un tip la altul.
fun findUser(id: Int): User?
val displayName = findUser(42)?.let { user ->
"${user.name} (${user.email})"
} ?: "Unknown user"
// let cu transformare de colecție
val numbers = listOf("1", "2", "3")
val parsed = numbers.firstOrNull()?.let {
it.toIntOrNull()
} ?: 0
În primul exemplu, let este apelat prin ?. — blocul se execută doar dacă findUser a returnat non-null. Lambda primește user prin it (poate fi redenumit pentru claritate) și returnează un string formatat. Dacă utilizatorul nu este găsit — operatorul Elvis ?: oferă o valoare implicită. În al doilea exemplu, let transformă un string în număr cu null potențial.
run — analogul lui let cu acces prin this, care returnează rezultatul lambdei. run este convenabil pentru calcule unde este necesar contextul obiectului, dar se returnează o valoare nouă. Apelul run() fără obiect (ca run { ... }) creează un domeniu temporar de vizibilitate pentru variabile. with — non-extensie cu acces prin this, potrivit pentru gruparea apelurilor fără înlănțuire.
// run ca calcul bazat pe context
val transformed = listOf(1, 2, 3).run {
filter { it > 1 }.map { it * 10 }
}
println(transformed) // [20, 30]
// with pentru gruparea apelurilor
val info = with(StringBuilder()) {
append("Name: ")
append("Alice")
toString()
}
În exemplu, run pe listă returnează rezultatul filtrării și mapării — transformarea în sine, nu lista. with primește StringBuilder ca argument (nu prin punct) și în interior lucrează cu this: append, append, toString. Rezultatul with — stringul info. Alegerea între run și with este adesea subiectivă, dar with este preferat când obiectul este transmis dintr-un alt loc fără înlănțuirea apelurilor.
with se deosebește de celelalte scope functions prin faptul că nu este o funcție de extensie. Ea primește obiectul ca prim argument, iar lambda ca al doilea. În interiorul lambdei, obiectul este accesibil prin this. with este convenabil pentru gruparea apelurilor metodelor obiectului fără a salva rezultatul sau când este necesară intrarea temporară „în context” pentru citirea mai multor proprietăți.
val user = User("Alice", "alice@example.com", "Admin")
val summary = with(user) {
"User $name has role $role and email $email"
}
println(summary)
// with pentru inițializarea componentei UI
with(TextView(context)) {
text = "Hello"
textSize = 18.0f
setTextColor(Color.BLUE)
}
În primul exemplu, with formează stringul summary, accesând proprietățile user direct prin this. Fără with ar trebui să scrieți „User ${user.name} has role ${user.role}” — repetarea multiplă a lui user. În al doilea exemplu, with grupează configurarea TextView: toate metodele și proprietățile sunt apelate pe un singur obiect fără repetare. Dezavantajul with — imposibilitatea utilizării în lanț, deoarece nu este extensie și nu returnează obiectul contextual.
Întrebări frecvente
Utilizați apply — returnează obiectul și oferă acces prin this, permițând setarea proprietăților fără repetarea numelui obiectului. also este potrivit dacă este necesar un parametru explicit it pentru distingerea de proprietățile obiectului.
let transmite contextul prin it (parametru explicit), run — prin this (destinatar implicit). let este convenabil pentru verificări null și transformări, run — pentru calcule cu context. Ambele returnează rezultatul lambdei.
with nu este extensie — primește obiectul ca argument. Utilizați with pentru gruparea apelurilor când nu este necesar un lanț. apply — extensie care returnează obiectul, convenabilă în inițializatori și modele builder.
Da, dar fiți atenți la this — this-urile imbricate creează confuzie. Utilizați let sau also cu nume explicite pentru contextele imbricate pentru a evita ambiguitatea la referirea la obiectul extern.
Toate scope functions sunt inline, deci nu creează overhead pentru clase anonime. Diferența de performanță între ele este neglijabilă. Alegerea trebuie să se bazeze pe lizibilitate și convenții, nu pe viteză.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și