Возврат и прыжки в Kotlin
Возврат и прыжки
В 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. Квалифицированный возврат позволяет нам вернуться из внешней функции. Самый важный вариант использования - возврат из лямбда-выражения. Напомним, когда мы пишем это:
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
// нелокальный возврат напрямую вызывающему foo()
if (it == 3) return
print(it)
}
println("эта точка недостижима")
}
Вывод:
12
Возвращаемое выражение возвращается из ближайшей включающей функции, то есть foo. (Обратите внимание, что такие нелокальные возвраты поддерживаются только для лямбда-выражений, передаваемых встроенным функциям.) Если нам нужно вернуться из лямбда-выражения, мы должны пометить его и квалифицировать возврат:
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
// локальный возврат к вызывающему лямбда-выражению,
// то есть циклу forEach
if (it == 3) return@lit
print(it)
}
print(" сделано с явной меткой")
}
Вывод:
1245 сделано с явной меткой
Теперь он возвращается только из лямбда-выражения. Часто удобнее использовать неявные метки: такая метка имеет то же имя, что и функция, в которую передается лямбда.
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
// локальный возврат к вызывающему лямбда,
// то есть циклу forEach
if (it == 3) return@forEach
print(it)
}
print(" сделано с неявной меткой")
}
Вывод:
1245 сделано с неявной меткой
В качестве альтернативы мы можем заменить лямбда-выражение анонимной функцией. Оператор return в анонимной функции будет возвращен из самой анонимной функции.
fun foo() {
listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
// локальный возврат вызывающему анонимной fun,
// то есть цикл forEach
if (value == 3) return
print(value)
})
print(" сделано с анонимной функцией")
}
Вывод:
1245 сделано с анонимной функцией
Обратите внимание, что использование локальных возвратов в предыдущих трех примерах аналогично использованию continue в обычных циклах. Прямого эквивалента для break не существует, но его можно смоделировать, добавив еще одну вложенную лямбду и не локально возвращаясь из нее:
fun foo() {
run loop@{
listOf(1, 2, 3, 4, 5).forEach {
// нелокальный возврат из лямбды,
// переданной для запуска
if (it == 3) return@loop
print(it)
}
}
print(" сделано с вложенным циклом")
}
Вывод:
12 сделано с вложенным циклом
При возврате значения парсер отдает предпочтение квалифицированному возврату, т.е.
return@a 1
означает "вернуть 1 на метке @a", а не "вернуть помеченное выражение (@a 1)".
Читайте также:
Комментарии
Отправить комментарий