Spec-Zone.ru › Kotlin 1.6

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

Оператор 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 перебирает всё, что предоставляет итератор. Это эквивалентно циклу foreach в языках вроде 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 в циклах. См. Возвращение и переходы.

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

© 2010–2022 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