Возвращение и переходы
В Kotlin есть три выражения структурного перехода:
returnпо умолчанию возвращает управление из ближайшей функции или анонимной функции.breakпрерывает ближайший цикл.continueпереходит к следующей итерации ближайшего цикла.
Все эти выражения могут быть использованы как часть более сложных выражений:
val s = person.name ?: return
Тип этих выражений — тип Nothing.
Метки 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 функции могут быть вложены с помощью лямбда-выражений, локальных функций и выражений объектов. Квалифицированные return позволяют вернуть управление из внешней функции. Самый важный случай — возврат из лямбда-выражения. Вспомним, что в следующем случае выражение return возвращает управление из ближайшей функции — foo:
//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return // non-local return directly to the caller of foo()
print(it)
}
println("this point is unreachable")
}
//sampleEnd
fun main() {
foo()
}
Обратите внимание, что такие нелокальные возвраты поддерживаются только для лямбда-выражений, переданных встроенным функциям. Чтобы вернуть управление из лямбда-выражения, пометьте его меткой и квалифицируйте return:
//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit // local return to the caller of the lambda - the forEach loop
print(it)
}
print(" done with explicit label")
}
//sampleEnd
fun main() {
foo()
}
Теперь возврат происходит только из лямбда-выражения. Зачастую удобнее использовать неявные метки, так как такая метка имеет то же имя, что и функция, которой передается лямбда.
//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@forEach // local return to the caller of the lambda - the forEach loop
print(it)
}
print(" done with implicit label")
}
//sampleEnd
fun main() {
foo()
}
В качестве альтернативы, можно заменить лямбда-выражение на анонимную функцию. Оператор return в анонимной функции вернёт управление из самой анонимной функции.
//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
if (value == 3) return // local return to the caller of the anonymous function - the forEach loop
print(value)
})
print(" done with anonymous function")
}
//sampleEnd
fun main() {
foo()
}
Обратите внимание, что использование локальных возвратов в предыдущих трёх примерах аналогично использованию continue в обычных циклах.
Нет непосредственного эквивалента для break, но его можно смоделировать, добавив ещё один вложенный лямбда-вызов и выполнив нелокальный возврат из него:
//sampleStart
fun foo() {
run loop@{
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@loop // non-local return from the lambda passed to run
print(it)
}
}
print(" done with nested loop")
}
//sampleEnd
fun main() {
foo()
}
При возвращении значения парсер отдаёт предпочтение квалифицированному возврату:
return@a 1
Это означает "вернуть 1 в метке @a", а не "вернуть помеченное выражение (@a 1)".
© 2010–2022 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/returns.html