Операторы перехода
В Kotlin определено три структурных оператора перехода:
returnпо умолчанию производит возврат из ближайшей содержащей его функции или анонимной функции;breakзавершает выполнение ближайшего окружающего его цикла;continueпродолжает выполнение цикла со следующего его шага, без обработки оставшегося кода текущей итерации.
Все эти выражения можно использовать как часть более крупных выражений:
val s = person.name ?: return
Эти выражения имеют тип Nothing.
Метки операторов break и continue
Любое выражение в Kotlin может быть помечено меткой label.
Метки имеют форму идентификатора, за которым следует знак @, например 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 переходит к следующей итерации этого цикла.
В некоторых случаях операторы
breakиcontinueможно применять нелокально, без явного определения меток. Такое нелокальное использование допустимо в лямбда-выражениях внутри окружающих инлайн-функций. {:.note}
Возврат к меткам
В Kotlin функции могут быть вложенными: для этого используются литералы функций, локальные функции и выражения объектов.
Квалифицированный return позволяет вернуться из внешней функции.
Самый важный сценарий - возврат из лямбда-выражения. Чтобы вернуться из лямбда-выражения, пометьте его меткой и
укажите эту метку у return:
//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit // локальный возврат к вызывающему коду лямбды - циклу forEach
print(it)
}
print(" выполнено с явной меткой")
}
//sampleEnd
fun main() {
foo()
}
{kotlin-runnable=“true” kotlin-min-compiler-version=“1.3”}
Теперь он возвращает только из лямбда-выражения. Зачастую намного более удобно использовать неявные метки, потому что такие метки имеют такое же имя, как и функция, к которой относится лямбда.
//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@forEach // локальный возврат к вызывающему коду лямбды - циклу forEach
print(it)
}
print(" выполнено с неявной меткой")
}
//sampleEnd
fun main() {
foo()
}
{kotlin-runnable=“true” kotlin-min-compiler-version=“1.3”}
В качестве альтернативы лямбда-выражению можно использовать анонимную функцию.
Оператор return возвращает из самой анонимной функции.
//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
if (value == 3) return // локальный возврат к вызывающему коду анонимной функции - циклу forEach
print(value)
})
print(" выполнено с анонимной функцией")
}
//sampleEnd
fun main() {
foo()
}
{kotlin-runnable=“true” kotlin-min-compiler-version=“1.3”}
Обратите внимание, что использование локальных возвратов в предыдущих трех примерах похоже на использование continue в обычных циклах.
Прямого эквивалента для break не существует, но его можно смоделировать: добавить внешнюю лямбду run и нелокально
вернуться из нее.
//sampleStart
fun foo() {
run loop@{
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@loop // нелокальный возврат из лямбды, переданной в run
print(it)
}
}
print(" выполнено с вложенным циклом")
}
//sampleEnd
fun main() {
foo()
}
{kotlin-runnable=“true” kotlin-min-compiler-version=“1.3”}
Нелокальный возврат здесь возможен, потому что вложенный вызов forEach() относится к инлайн-функции.
При возвращении значения парсер отдаёт предпочтение квалифицированному return:
return@a 1
Это означает “вернуть 1 по метке @a”, а не “вернуть помеченное выражение (@a 1)”.
В некоторых случаях из лямбда-выражения можно вернуть значение без меток. Такие нелокальные возвраты находятся в лямбде, но завершают окружающую инлайн-функцию. {:.note}