Added kotlin guide. (WIP) (15.10.26)

This commit is contained in:
2026-10-15 00:24:21 +03:00
parent dc82207723
commit da3ad9dd1a
13 changed files with 2120 additions and 0 deletions
@@ -0,0 +1,159 @@
---
title: Циклы и диапазоны
description: for-in, диапазоны и прогрессии, while, метки и отсутствие классического for
tags:
- kotlin
- syntax
---
В Kotlin один цикл обхода - `for (x in source)`. Классического `for (int i = 0; i < n; i++)` нет: его роль выполняют диапазоны.
## Диапазоны
```kotlin
for (i in 1..5) print(i) // 12345 — включая 5
for (i in 1..<5) print(i) // 1234 — исключая 5
for (i in 5 downTo 1) print(i) // 54321
for (i in 1..10 step 3) print(i) // 1 4 7 10
for (c in 'a'..'e') print(c) // abcde
```
| Конструкция | Смысл |
|---|---|
| `a..b` | от `a` до `b` включительно |
| `a..<b` | от `a` до `b`, не включая `b` |
| `a until b` | то же, что `a..<b` (старая форма) |
| `a downTo b` | по убыванию, включительно |
| `step n` | с шагом `n` |
Шаг всегда положительный, даже в `downTo`: направление задаёт `downTo`, а не знак шага.
Диапазон - это объект, его можно хранить и проверять:
```kotlin
val valid = 1..100
println(42 in valid) // true
println(valid.first) // 1
println(valid.last) // 100
println((1..10 step 3).last) // 10
```
## Обход по индексам
```kotlin
val list = listOf("a", "b", "c")
for (i in list.indices) print(i) // 012
for (i in 0..<list.size) print(i) // 012 — то же самое
for (item in list) print(item) // abc — предпочтительно
for ((i, item) in list.withIndex()) { // 0:a 1:b 2:c
print("$i:$item ")
}
```
`withIndex()` возвращает пары, которые тут же разбираются деструктуризацией ([Деструктуризация](../Работа%20с%20данными/Деструктуризация.md)).
## Обход коллекций и Map
```kotlin
val map = mapOf("a" to 1, "b" to 2)
for ((key, value) in map) {
println("$key=$value")
}
```
`for` работает с любым типом, у которого есть функция `iterator()` - включая свои классы.
## while и do-while
```kotlin
var i = 0
while (i < 3) {
print(i) // 012
i++
}
do {
val line = readLine()
} while (line != null) // тело выполнится минимум один раз
```
Переменная, объявленная в `do`, видна в условии `while` - такого в Java нет.
## break и continue
```kotlin
for (i in 1..10) {
if (i == 3) continue // пропустить итерацию
if (i == 5) break // выйти из цикла
print(i) // 124
}
```
## Метки
Метка - идентификатор с `@`. Нужна, чтобы выйти из внешнего цикла:
```kotlin
outer@ for (i in 1..3) {
for (j in 1..3) {
if (j == 2) continue@outer // к следующей i
if (i == 3) break@outer // выход из обоих циклов
print("$i$j ") // 11 21
}
}
```
## Циклы - не выражения
`for` и `while` возвращают `Unit`, присвоить их результат нельзя. Если нужен результат обхода - это операции над коллекциями:
```kotlin
val doubled = (1..5).map { it * 2 } // [2, 4, 6, 8, 10]
val evens = (1..10).filter { it % 2 == 0 } // [2, 4, 6, 8, 10]
val sum = (1..100).sum() // 5050
```
В идиоматичном Kotlin явные циклы встречаются редко. Подробнее: [Операции над коллекциями](../../Коллекции/Операции.md)
## repeat
Когда индекс не нужен:
```kotlin
repeat(3) { println("повтор") }
repeat(3) { i -> println("итерация $i") } // индекс доступен, с нуля
```
Это не оператор, а [inline-функция](../../Функциональный%20Kotlin/Inline-функции.md) стандартной библиотеки.
> [!info] Отличия от Java
> | Java | Kotlin |
> |---|---|
> | `for (int i=0; i<n; i++)` | `for (i in 0..<n)` |
> | `for (T x : collection)` | `for (x in collection)` |
> | `label: for (...)` | `outer@ for (...)` |
> | `break label;` | `break@outer` |
> | три части в заголовке `for` | только `in` |
> | нет диапазонов | `1..10`, `step`, `downTo` |
>
> Что потеряли: заголовок `for` с несколькими переменными и произвольным условием. Если нужна такая логика - пишется `while`.
>
> Сравнить: [Циклы в Java](../../../Программирование%20на%20Java/Синтаксис%20и%20типы/Базовый%20синтаксис/Циклы.md)
> [!warning] Подводные камни
> **`1..5` включает 5.** Самая частая ошибка при переходе с Java: индексы массива - это `0..<size`, а не `0..size`:
> ```kotlin
> val list = listOf("a", "b", "c")
> // for (i in 0..list.size) println(list[i]) // IndexOutOfBounds на i=3
> for (i in 0..<list.size) println(list[i]) // верно
> for (i in list.indices) println(list[i]) // ещё лучше
> ```
>
> **`downTo` со `step` требует положительного шага:**
> ```kotlin
> for (i in 5 downTo 1 step 2) print(i) // 531
> // for (i in 5 downTo 1 step -2) // IllegalArgumentException в рантайме
> ```
>
> **Пустой диапазон не ошибка, просто ноль итераций:**
> ```kotlin
> for (i in 5..1) print(i) // ничего не напечатает
> ```
> Молчаливый баг, если границы перепутаны. `(5..1).isEmpty()` - `true`.
>
> **Коллекцию нельзя изменять во время обхода:**
> ```kotlin
> val list = mutableListOf(1, 2, 3)
> // for (x in list) if (x == 2) list.remove(x) // ConcurrentModificationException
> list.removeAll { it == 2 } // правильный способ
> ```
>
> **Диапазон `Long` и `Char` есть, а `Double` - нет.** `1.0..2.0` создаст `ClosedFloatingPointRange`: проверять `in` можно, но обойти циклом - нельзя (нет `iterator()`).
Дополнительно: [Операции над коллекциями](../../Коллекции/Операции.md)
Далее: [Строковые шаблоны и вывод](Строковые%20шаблоны%20и%20вывод.md)