Управление циклами Kotlin

Цикл For

Цикл for может перебирать любой объект, предоставляющий итератор. Синтаксис следующий:

for (item in collection) print(item)

Тело цикла может быть блоком кода:

for (item: Int in ints) {
    // ……
}

Как упоминалось выше, for может перебирать любой объект, предоставляющий итератор.

Если вы хотите обойти массив или список по индексу, можно сделать так:

for (i in array.indices) {
    print(array[i])
}

Обратите внимание, что эта «итерация по диапазону» компилируется в оптимизированную реализацию без создания дополнительных объектов.

В качестве альтернативы можно использовать библиотечную функцию withIndex:

for ((index, value) in array.withIndex()) {
    println("the element at $index is $value")
}

Пример

Итерация по коллекции:

fun main(args: Array<String>) {
    val items = listOf("apple", "banana", "kiwi")
    for (item in items) {
        println(item)
    }

    for (index in items.indices) {
        println("item at $index is ${items[index]}")
    }
}

Результат вывода:

apple
banana
kiwi
item at 0 is apple
item at 1 is banana
item at 2 is kiwi

Циклы while и do...while

while — самый базовый цикл; его структура такова:

while( 布尔表达式 ) {
  //循环内容
}

Цикл do...while Для оператора while, если условие не выполнено, в цикл нельзя войти. Но иногда нам нужно выполнить тело хотя бы один раз, даже если условие не выполнено.

Цикл do...while похож на цикл while, за исключением того, что цикл do...while выполняется как минимум один раз.

do {
       //代码语句
}while(布尔表达式);

Пример

fun main(args: Array<String>) {
    println("----while 使用-----")
    var x = 5
    while (x > 0) {
        println( x--)
    }
    println("----do...while 使用-----")
    var y = 5
    do {
        println(y--)
    } while(y>0)
}

Результат вывода:

----while 使用-----
5
4
3
2
1
----do...while 使用-----
5
4
3
2
1

Возвраты и переходы

В Kotlin есть три структурированных выражения перехода:

  • returnПо умолчанию выполняет возврат из функции или анонимной функции, которая непосредственно его окружает.
  • breakЗавершает цикл, который непосредственно его окружает.
  • continueПереходит к следующей итерации цикла, который непосредственно его окружает.

В циклах Kotlin поддерживает традиционные операторы break и continue.

fun main(args: Array<String>) {
    for (i in 1..10) {
        if (i==3) continue  // i 为 3 时跳过当前循环,继续下一次循环
        println(i)
        if (i>5) break   // i 为 6 时 跳出循环
    }
}

Результат вывода:

1
2
4
5
6

Метки break и continue

В Kotlin любое выражение можно пометить меткой. Формат метки — идентификатор, за которым следует символ @, например: abc@ и fooBar@ — допустимые метки. Чтобы пометить выражение, мы просто ставим метку перед ним.

loop@ for (i in 1..100) {
    // ……
}

Теперь мы можем использовать метки, чтобы уточнить break или continue:

loop@ for (i in 1..100) {
    for (j in 1..100) {
        if (……) break@loop
    }
}

break с меткой переходит к точке выполнения сразу после цикла, указанного меткой. continue с меткой переходит к следующей итерации цикла, указанного меткой.

Возврат по меткам

В Kotlin есть функциональные литералы, локальные функции и объектные выражения. Поэтому функции Kotlin могут быть вложенными. Помеченный return позволяет вернуться из внешней функции. Одно из наиболее важных применений — возврат из лямбда-выражения. Вспомните, когда мы пишем:

fun foo() {
    ints.forEach {
        if (it == 0) return
        print(it)
    }
}

Это выражение return выполняет возврат из функции, непосредственно его окружающей, то есть из foo. (Обратите внимание, что такой нелокальный return поддерживается только для лямбда-выражений, передаваемых в inline-функции.) Если нам нужно вернуться из лямбда-выражения, мы должны пометить его и использовать эту метку для уточнения return.

fun foo() {
    ints.forEach lit@ {
        if (it == 0) return@lit
        print(it)
    }
}

Теперь возврат произойдёт только из лямбда-выражения. Обычно удобнее использовать неявную метку. Эта метка имеет то же имя, что и функция, принимающая лямбду.

fun foo() {
    ints.forEach {
        if (it == 0) return@forEach
        print(it)
    }
}

В качестве альтернативы мы можем заменить лямбда-выражение анонимной функцией. Оператор return внутри анонимной функции выполнит возврат из самой анонимной функции.

fun foo() {
    ints.forEach(fun(value: Int) {
        if (value == 0) return
        print(value)
    })
}

Когда нужно вернуть значение, парсер предпочитает return с указанием метки, то есть

return@a 1

Это означает «return 1 из метки @a», а не «вернуть выражение с аннотацией метки (@a 1)».

Другие расширения