Глиф Учебники

Урок 5. Циклы for и while, диапазоны

Курс «Kotlin» · урок 5 из 10 · 3 минуты чтения

Цикл повторяет команды несколько раз: вывести числа от 1 до 100, сложить всё введённое, ждать правильного ответа. В Kotlin два основных цикла: for — по заранее известному набору значений, и while — пока верно условие.

for и диапазоны

Kotlin
fun main() {
    for (i in 1..3) {
        println("Step $i")
    }
}
Вывод
Step 1
Step 2
Step 3

1..3 — диапазон от 1 до 3 включительно. Цикл for (i in 1..3) по очереди кладёт в переменную i каждое число диапазона и выполняет тело цикла. Переменную i объявлять заранее не нужно, и val или var перед ней не пишут.

Диапазоны бывают разные. Чтобы увидеть, какие числа в них входят, удобно превратить диапазон в список — toList():

Kotlin
fun main() {
    println((1..5).toList())
    println((0 until 5).toList())
    println((0..<5).toList())
    println((1..10 step 2).toList())
    println((10 downTo 1).toList())
    println((10 downTo 1 step 3).toList())
    println((5..1).toList())
    println(('a'..'e').toList())
}
Вывод
[1, 2, 3, 4, 5]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4]
[1, 3, 5, 7, 9]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[10, 7, 4, 1]
[]
[a, b, c, d, e]
ЗаписьЧто значит
1..5от 1 до 5, обе границы входят
0 until 5 или 0..<5от 0 до 4 — правая граница не входит
1..10 step 2с шагом 2: 1, 3, 5, 7, 9
10 downTo 1обратный отсчёт от 10 до 1
5..1пустой диапазон — цикл не выполнится ни разу

Последняя строка — частая ошибка: для счёта назад нужен downTo, а не ...

0 1 2 3 4 5 6 7 8 9 10 1..5 1 2 3 4 5 0 until 5 или 0..<5 0 1 2 3 4 5 1..10 step 2 +2 1 3 5 7 9 10 downTo 1 step 3 −3 10 7 4 1 5..1 пусто — ни одного шага входит в диапазон граница не входит
Какие числа входят в диапазоны 1..5, 0 until 5, 1..10 step 2 и 10 downTo 1 step 3; диапазон 5..1 пуст, и цикл по нему не выполнится ни разу.

until удобен для номеров элементов: в списке из 5 элементов номера от 0 до 4, то есть 0 until 5.

Сумма в цикле

Типичная задача — сложить числа от 1 до n:

Kotlin
fun main() {
    val n = readln().toInt()
    var sum = 0
    for (i in 1..n) {
        sum += i
    }
    println(sum)
}
Ввод
100
Вывод
5050

Переменная sum объявлена через var до цикла: в цикле она меняется, а после него нужна для вывода.

Перебор строки

for перебирает не только числа, но и символы строки:

Kotlin
fun main() {
    val word = "banana"
    var count = 0
    for (c in word) {
        if (c == 'a') {
            count++
        }
    }
    println(count)
}
Вывод
3

Так же for перебирает элементы списков — об этом в уроке Коллекции.

while

while повторяет тело, пока условие верно. Условие проверяется перед каждым повтором:

Kotlin
fun main() {
    var n = 1
    while (n < 100) {
        n *= 2
    }
    println(n)
}
Вывод
128

Число удваивается: 1, 2, 4, …, 64, 128. При 128 условие n < 100 становится неверным, и цикл заканчивается.

Если условие while никогда не станет неверным, цикл будет крутиться бесконечно, и программа зависнет. Проверьте, что в теле цикла меняется то, от чего зависит условие. Остановить зависшую программу в IntelliJ IDEA — красный квадрат в окне Run, в командной строке — Ctrl+C.

do-while

do { ... } while (условие) сначала выполняет тело, а потом проверяет условие — тело выполнится хотя бы один раз. Удобно для ввода: читать числа, пока не введут 0:

Kotlin
fun main() {
    var sum = 0
    do {
        val x = readln().toInt()
        sum += x
    } while (x != 0)
    println(sum)
}
Ввод
5
3
10
0
Вывод
18

Переменная x объявлена внутри тела, но в условии while она видна — в Kotlin так можно.

while (…) { … } сначала проверка, потом тело условие да тело цикла нет после цикла может не выполниться ни разу do { … } while (…) сначала тело, потом проверка тело цикла условие да нет после цикла тело — хотя бы один раз
while проверяет условие до тела и может не выполнить его ни разу, а do-while сначала выполняет тело и проверяет условие после него.

repeat

Если нужно просто повторить действие несколько раз, а номер повтора не важен, есть repeat:

Kotlin
fun main() {
    repeat(3) {
        println("Hi")
    }
}
Вывод
Hi
Hi
Hi

break и continue

Kotlin
fun main() {
    for (i in 1..10) {
        if (i % 3 == 0) continue
        if (i > 7) break
        println(i)
    }
}
Вывод
1
2
4
5
7

Числа 3 и 6 пропущены через continue. На 8 сработал break, и цикл закончился, до 9 и 10 дело не дошло.

for (i in 1..10) { if (i % 3 == 0) continue if (i > 7) break println(i) } вывод — println(i) continue — пропуск, к следующему i break — выход из цикла не дошло значения i по шагам 1 2 3 continue 4 5 6 continue 7 8 break 9 10 выход из цикла вывод: 1 2 4 5 7
Ход цикла по i от 1 до 10: на 3 и 6 continue пропускает вывод, на 8 break завершает цикл, до 9 и 10 дело не доходит.

Вложенные циклы и метки

Цикл можно поставить внутрь другого. break во внутреннем цикле выходит только из него. Чтобы выйти сразу из обоих, внешнему циклу дают метку — имя со знаком @:

Kotlin
fun main() {
    outer@ for (i in 1..5) {
        for (j in 1..5) {
            if (i * j == 12) {
                println("$i * $j = 12")
                break@outer
            }
        }
    }
}
Вывод
3 * 4 = 12

break@outer выходит из цикла с меткой outer. Без метки программа вывела бы ещё 4 * 3 = 12.

Чего в Kotlin нет

Привычного по C и Java цикла for (int i = 0; i < n; i++) в Kotlin нет. Его заменяют диапазоны:

C, JavaKotlin
for (i = 0; i < n; i++)for (i in 0 until n)
for (i = 1; i <= n; i++)for (i in 1..n)
for (i = n; i >= 1; i--)for (i in n downTo 1)
for (i = 0; i < n; i += 2)for (i in 0 until n step 2)

Коротко

Проверьте себя

1. Какие числа перебирает for (i in 0 until 4)?
2. Сколько раз выполнится тело цикла for (i in 10..1)?
3. Что выведет программа?
Kotlin
fun main() {
    for (i in 1..10 step 4) {
        print(i)
    }
}
4. Чем do-while отличается от while?
5. Что делает continue в цикле?