run în Kotlin

Rulează un bloc în care obiectul este this și returnează rezultatul blocului; with face același lucru, dar primește obiectul ca argument.

Sintaxă
inline fun <T, R> T.run(block: T.() -> R): R
inline fun <R> run(block: () -> R): R
inline fun <T, R> with(receiver: T, block: T.() -> R): R

Ce face run

obiect.run { ... } rulează blocul cu obiectul ca this: în interior îi poți folosi direct proprietățile și metodele, fără să scrii numele obiectului. Rezultatul este ultima expresie din bloc, ca la let.

with(obiect) { ... } este aceeași idee, scrisă altfel: obiectul este argument, nu stă înaintea punctului. Se citește „cu obiectul ăsta, fă…” și este folosit când ai mai multe operații pe același obiect. Spre deosebire de run, nu poate fi folosit cu ?..

Există și run { ... } fără obiect: rulează pur și simplu blocul și îi returnează rezultatul. Este util pentru a calcula o valoare în câțiva pași, cu variabile care nu „scapă” în afara blocului.

Parametri

Parametru Descriere
block: T.() -> R Blocul de cod, în care this este obiectul. Ultima expresie este rezultatul.
receiver: T Doar la with: obiectul pe care lucrează blocul.

Ce returnează

Rezultatul blocului (ultima expresie).

Exemple

Exemplul 1: run și with pe același obiect

În ambele blocuri, nume, note și media() se referă la obiectul student, fără să-l mai numim.

class Student(val nume: String, val note: List<Int>) {
    fun media() = note.average()
}

fun main() {
    val ana = Student("Ana", listOf(9, 10, 8))

    val raport = ana.run {
        "$nume are ${note.size} note și media ${media()}"
    }
    println(raport)

    val promovat = with(ana) {
        println("Verific notele lui $nume...")
        note.all { it >= 5 }
    }
    println("Promovat: $promovat")
}

Rezultat

Ana are 3 note și media 9.0
Verific notele lui Ana...
Promovat: true

Exemplul 2: run fără obiect pentru un calcul în pași

Variabilele pret și tva există doar în bloc; în afara lui rămâne doar rezultatul.

fun main() {
    val total = run {
        val pret = 250.0
        val tva = pret * 0.19
        pret + tva
    }
    println("Total cu TVA: $total lei")
}

Rezultat

Total cu TVA: 297.5 lei

Exemplul 3: ?.run pentru o valoare care poate lipsi

Ca la let, cu ?. blocul rulează doar pentru valori diferite de null. Aici this este textul, deci length și uppercase() se aplică direct.

fun main() {
    val orase: List<String?> = listOf("Iași", null, "Brașov")
    for (oras in orase) {
        val info = oras?.run { "${uppercase()} ($length litere)" } ?: "oraș necunoscut"
        println(info)
    }
}

Rezultat

IAȘI (4 litere)
oraș necunoscut
BRAȘOV (6 litere)

Greșeli frecvente

  • Confunzi run cu apply. run returnează rezultatul blocului; apply returnează obiectul. Dacă vrei obiectul configurat, folosește apply.
  • Scrii with(x) { } când x poate fi null. with nu are variantă sigură; folosește x?.run { }.
  • În bloc, un nume local cu același nume ca o proprietate o „ascunde”, iar codul folosește variabila locală fără să-ți dai seama. Evită numele care se suprapun.

Comenzi înrudite

  • let: Rulează un bloc de cod cu valoarea ca parametru it și returnează rezultatul blocului; des folosit cu ?. pentru valori null.
  • apply: Configurează un obiect într-un bloc în care obiectul este this, apoi returnează chiar obiectul.
  • also: Face o acțiune în plus cu un obiect (afișare, verificare, log) și returnează obiectul neschimbat.