Ghid Idiomatic pentru Funcțiile de Domeniu în Kotlin: let, run, with, apply și also în Kotlin

Ghid complet pentru cele 5 Scope Functions din Kotlin: diferențele dintre let, run, with, apply și also, matricea de decizie tehnică bazată pe context object (this vs it) și valoarea returnată.

Sintaxă
obj.let { it.save() } | obj.apply { name = '...' } | with(obj) { ... } | obj.also { log(it) }

Biblioteca standard Kotlin include cinci funcții de extensie celebre denumite Funcții de Domeniu (Scope Functions): let, run, with, apply și also. Scopul lor unic este de a executa un bloc de cod în contextul unui anumit obiect, făcând codul mult mai concis și lizibil.

Deoarece realizează operațiuni similare, alegerea funcției corecte creează frecvent confuzie. Diferența se rezumă strict la doi parametri: cum este referit obiectul în lambda (this vs it) și ce returnează funcția (obiectul însuși vs rezultatul lambda).

Matricea de Decizie a Funcțiilor de Domeniu
Funcție Obiect de Context Valoare Returnată Scenariu Optim de Utilizare
let it (argument lambda) Rezultatul lambda Verificare de nenulabilitate: valoare?.let { ... } și transformări locale de date.
apply this (receptor) Obiectul de context Configurarea proprietăților unui obiect la instanțiere (Builder pattern).
also it (argument lambda) Obiectul de context Efecte secundare fără a modifica obiectul (logging, audit, depanare).
run this (receptor) Rezultatul lambda Calcularea unui rezultat pe baza unui obiect sau inițializare complexă.
with this (transmis ca parametru) Rezultatul lambda Gruparea apelurilor de metode multiple pe un obiect deja existent.
Exemple Practice Idiomatice
// 1. 'apply' pentru configurare de obiecte (returnează instanța configurată):
val buton = Buton().apply {
    text = "Trimite Comanda"
    esteActiv = true
    culoareFundal = "#007BFF"
}

// 2. 'also' pentru efecte colaterale (logging):
val utilizator = creeazaUtilizator().also {
    println("Utilizator creat în sistem cu ID-ul: ${it.id}")
}

// 3. 'let' pentru operațiuni sigure pe valori opționale:
val email: String? = obtineEmailOptional()
email?.let { textClar ->
    trimiteNotificare(textClar) // Rulează STRICT dacă email != null!
}

// 4. 'run' pentru evaluare și returnare rezultat:
val lungimeDescriere = utilizator.run {
    println("Calculare dimensiune pentru $nume")
    descriere.length
}