Range-uri (.., ..<, until, downTo, step) în Kotlin

Controlul execuției Kotlin 1.0 (..<: Kotlin 1.9)

Intervale de numere sau caractere: .. include capătul, ..< și until îl exclud, downTo numără invers, step sare.

Sintaxă
1..10           // 1, 2, ..., 10
0..<10          // 0, 1, ..., 9
0 until 10      // la fel ca 0..<10
10 downTo 1     // 10, 9, ..., 1
0..100 step 10  // 0, 10, 20, ..., 100

Ce face Range-uri (.., ..<, until, downTo, step)

Un range (interval) descrie toate valorile dintre două capete. 1..10 include ambele capete. 0..<10 (din Kotlin 1.9) și 0 until 10 exclud capătul de sus, potrivit pentru poziții dintr-o listă. 10 downTo 1 merge descrescător, iar step 2 sare din doi în doi. Merg cu Int, Long, Char și, pentru verificări cu in, cu Double sau String.

Range-urile se folosesc în for (for (i in 1..5)), în verificări (nota in 1..10), în when și cu funcții de colecții: (1..5).map { it * it }, (1..100).sum(). Un range nu ține în memorie toate numerele: are doar capetele și pasul.

Dacă începutul este mai mare decât sfârșitul, 5..1 este gol (nu numără invers). Ai proprietățile first, last, step și funcțiile reversed(), isEmpty(), count().

Exemple

Exemplul 1: Toate formele

joinToString afișează valorile fiecărui interval pe un rând.

fun main() {
    println("1..5       : " + (1..5).joinToString())
    println("0..<5      : " + (0..<5).joinToString())
    println("0 until 5  : " + (0 until 5).joinToString())
    println("5 downTo 1 : " + (5 downTo 1).joinToString())
    println("0..20 step 5: " + (0..20 step 5).joinToString())
    println("'a'..'e'   : " + ('a'..'e').joinToString(""))
    println("5..1 gol?  : " + (5..1).isEmpty())
}

Rezultat

1..5       : 1, 2, 3, 4, 5
0..<5      : 0, 1, 2, 3, 4
0 until 5  : 0, 1, 2, 3, 4
5 downTo 1 : 5, 4, 3, 2, 1
0..20 step 5: 0, 5, 10, 15, 20
'a'..'e'   : abcde
5..1 gol?  : true

Exemplul 2: Calcule cu intervale

Un interval se folosește ca o colecție: sum, filter, map.

fun main() {
    println("Suma 1..100 = ${(1..100).sum()}")
    val pare = (1..20).filter { it % 2 == 0 }
    println("Numere pare: $pare")
    val patrate = (1..5).map { it * it }
    println("Pătrate: $patrate")
    val ani = 2020..2026 step 2
    println("Ani pari: ${ani.toList()}, primul ${ani.first}, ultimul ${ani.last}")
}

Rezultat

Suma 1..100 = 5050
Numere pare: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Pătrate: [1, 4, 9, 16, 25]
Ani pari: [2020, 2022, 2024, 2026], primul 2020, ultimul 2026

Exemplul 3: Verificări de interval

Cu in, intervalul poate fi și de Double (temperatură) sau de text (ordine alfabetică).

fun main() {
    val confort = 20.0..24.5
    for (t in listOf(19.5, 22.0, 24.5)) {
        println("$t °C în zona de confort: ${t in confort}")
    }
    val primaJumatate = "A".."M"
    for (nume in listOf("Ana", "Mihai", "Radu")) {
        println("$nume în grupa A-M: ${nume in primaJumatate}")
    }
}

Rezultat

19.5 °C în zona de confort: false
22.0 °C în zona de confort: true
24.5 °C în zona de confort: true
Ana în grupa A-M: true
Mihai în grupa A-M: false
Radu în grupa A-M: false

Greșeli frecvente

  • for (i in 0..lista.size): .. include capătul, deci depășește lista cu o poziție. Folosește 0..<lista.size sau lista.indices.
  • for (i in 10..1) pentru numărătoare inversă: intervalul este gol, bucla nu rulează deloc. Scrie 10 downTo 1.
  • "Mihai" in "A".."M" dă false: textele se compară lexicografic, iar „Mihai” vine după „M”.

Comenzi înrudite

  • for: Parcurge pe rând elementele unei colecții, ale unui interval sau ale oricărui obiect care are iterator().
  • in și !in: in verifică dacă o valoare aparține unui interval, unei colecții sau unui text; tot in se folosește în for.
  • when: Alege o ramură după valoarea unei expresii sau după prima condiție adevărată; înlocuiește switch din alte limbaje.
  • infix: infix permite apelarea unei funcții cu un parametru fără punct și paranteze: a to b în loc de a.to(b).