Added kotlin guide. (WIP) (15.10.26)
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user