Spec-Zone.ru › Kotlin 1.8

Условные операторы и циклы

Оператор if

В Kotlin оператор if является выражением: он возвращает значение. Поэтому нет оператора тернарного условия (condition ? then : else), так как обычный оператор if хорошо выполняет эту роль.

var max = a 
if (a < b) max = b

// With else 
var max: Int
if (a > b) {
    max = a
} else {
    max = b
}
 
// As expression 
val max = if (a > b) a else b

Ветви выражения if могут быть блоками. В этом случае значением блока является последнее выражение в нём:

val max = if (a > b) {
    print("Choose a")
    a
} else {
    print("Choose b")
    b
}

Если вы используете оператор if как выражение, например, для возврата его значения или присваивания переменной, ветвь else обязательна.

Оператор when

Оператор when определяет условное выражение с несколькими ветвями. Он похож на оператор switch в языках C-подобного семейства. Его простая форма выглядит так.

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> {
        print("x is neither 1 nor 2")
    }
}

Оператор when последовательно сравнивает свой аргумент с условиями всех ветвей, пока не будет выполнено условие какой-либо из них.

Оператор when может быть использован как выражение или как оператор. Если он используется как выражение, значение первой удовлетворяющей ветви становится значением всего выражения. Если он используется как оператор, значения отдельных ветвей игнорируются. Как и в операторе if, каждая ветвь может быть блоком, а его значением является значение последнего выражения в блоке.

Ветвь else выполняется, если ни одно из условий других ветвей не удовлетворяется.

Если оператор when используется как выражение, ветвь else обязательна, если компилятор не может доказать, что все возможные случаи покрыты условиями ветвей, например, с помощью элементов enum класса и подтипов sealed класса.

enum class Bit {
  ZERO, ONE
}

val numericValue = when (getRandomBit()) {
    Bit.ZERO -> 0
    Bit.ONE -> 1
    // 'else' is not required because all cases are covered
}

В операторах when, определяемых как операторы, ветвь else обязательна при следующих условиях:

  • субъект оператора when имеет тип Boolean, enum или sealed (или их nullable аналоги).

  • ветви оператора when не покрывают все возможные случаи для данного объекта.

enum class Color {
  RED, GREEN, BLUE
}

when (getColor()) {  
    Color.RED -> println("red")
    Color.GREEN -> println("green")   
    Color.BLUE -> println("blue")
    // 'else' is not required because all cases are covered
}

when (getColor()) {
  Color.RED -> println("red") // no branches for GREEN and BLUE
  else -> println("not red") // 'else' is required
}

Для определения общего поведения для нескольких случаев объедините их условия в одной строке с запятыми:

when (x) {
    0, 1 -> print("x == 0 or x == 1")
    else -> print("otherwise")
}

В качестве условий ветвей можно использовать произвольные выражения (не только константы).

when (x) {
    s.toInt() -> print("s encodes x")
    else -> print("s does not encode x")
}

Вы также можете проверить, является ли значение in или !in элементом диапазона или коллекции:

when (x) {
    in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10..20 -> print("x is outside the range")
    else -> print("none of the above")
}

Другой вариант – проверка, является ли значение is или !is определённого типа. Обратите внимание, что благодаря «умным приведениям типов» вы можете обращаться к методам и свойствам типа без дополнительных проверок.

fun hasPrefix(x: Any) = when(x) {
    is String -> x.startsWith("prefix")
    else -> false
}

Оператор when также может быть использован как замена цепочки операторов if-else-if.

when {
    x.isOdd() -> print("x is odd")
    y.isEven() -> print("y is even")
    else -> print("x+y is odd")
}

Вы можете поймать объект оператора when в переменную, используя следующий синтаксис:

fun Request.getBody() =
    when (val response = executeRequest()) {
        is Success -> response.body
        is HttpError -> throw HttpException(response.status)
    }

Область действия переменной, введённой в операторе when, ограничена телом оператора when.

Циклы for

Цикл for перебирает элементы любой последовательности, предоставляющей итератор. Это эквивалентно циклу for в языках вроде C#. Синтаксис цикла for:

for (item in collection) print(item)

Тело цикла for может быть блоком.

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

Как уже упоминалось, цикл for перебирает любой объект, который предоставляет итератор. Это означает, что:

  • у него должен быть метод или расширяющее свойство iterator() который возвращает Iterator<>:

    • у него должен быть метод или расширяющее свойство next()

    • у него должен быть метод или расширяющее свойство hasNext() который возвращает Boolean.

Все эти три метода должны быть отмечены как operator.

Для перебора диапазона чисел используйте выражение диапазона:

fun main() {
//sampleStart
    for (i in 1..3) {
        println(i)
    }
    for (i in 6 downTo 0 step 2) {
        println(i)
    }
//sampleEnd
}

Цикл for по диапазону или массиву компилируется в индексный цикл, который не создаёт объект итератора.

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

fun main() {
val array = arrayOf("a", "b", "c")
//sampleStart
    for (i in array.indices) {
        println(array[i])
    }
//sampleEnd
}

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

fun main() {
    val array = arrayOf("a", "b", "c")
//sampleStart
    for ((index, value) in array.withIndex()) {
        println("the element at $index is $value")
    }
//sampleEnd
}

Циклы while

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

  • цикл while проверяет условие, и если оно выполняется, выполняет тело и возвращается к проверке условия.

  • цикл do-while выполняет тело, а затем проверяет условие. Если условие выполняется, цикл повторяется. Таким образом, тело цикла do-while выполняется как минимум один раз, независимо от условия.

while (x > 0) {
    x--
}

do {
    val y = retrieveData()
} while (y != null) // y is visible here!

Операторы break и continue в циклах

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

Последнее изменение: 10 января 2023
Проверки и приведения типов Возврат и переходы

© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/control-flow.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API