`break` и` continue` в `forEach` в Котлине
У Kotlin очень хорошие функции итерации, такие как forEach
или repeat
, но я не могу заставить операторы break
и continue
работать с ними (как локальные, так и нелокальные):
repeat(5) {
break
}
(1..5).forEach {
[email protected]
}
Цель состоит в том, чтобы имитировать обычные циклы с функциональным синтаксисом как можно ближе. Это было определенно возможно в некоторых старых версиях Kotlin, но я изо всех сил пытаюсь воспроизвести синтаксис.
Проблема может быть ошибкой с метками (M12), но я думаю, что первый пример должен работать в любом случае.
Мне кажется, что я где-то читал о специальном трюке/аннотации, но я не мог найти ссылку на эту тему. Может выглядеть так:
public inline fun repeat(times: Int, @loop body: (Int) -> Unit) {
for (index in 0..times - 1) {
body(index)
}
}
Ответы
Ответ 1
Редактирование:
Согласно старым документам Kotlin - ссылка не работает, это должно быть возможно с использованием аннотаций. Однако он еще не реализован.
Разрыв и продолжение для пользовательских структур управления не реализованы еще
проблема для этой функции уже 3 года, поэтому я думаю, что она не будет исправлена.
Оригинальный ответ:
Поскольку вы предоставляете (Int) -> Unit
, вы не можете от него отказаться, так как компилятор не знает, что он используется в цикле.
У вас есть несколько вариантов:
Используйте обычный цикл for:
for (index in 0..times - 1) {
// your code here
}
Если цикл является последним кодом в методе
вы можете использовать return
, чтобы выйти из метода (или return value
, если это не метод unit
).
Используйте метод
Создайте собственный метод метода повторения, который возвращает Boolean
для продолжения.
public inline fun repeatUntil(times: Int, body: (Int) -> Boolean) {
for (index in 0..times - 1) {
if (!body(index)) break
}
}
Ответ 2
Это будет печатать от 1 до 5. [email protected]
действует как ключевое слово continue
в Java, что означает, что в этом случае он все равно выполняет каждый цикл, но пропускает следующую итерацию, если значение больше 5.
fun main(args: Array<String>) {
val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
nums.forEach {
if (it > 5) [email protected]
println(it)
}
}
Это будет печатать от 1 до 10, но пропускает 5.
fun main(args: Array<String>) {
val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
nums.forEach {
if (it == 5) [email protected]
println(it)
}
}
Попробуйте их на игровой площадке Котлин.
Ответ 3
Вы можете использовать return from lambda expression, который имитирует continue
или break
в зависимости от вашего использования.
Об этом говорится в следующем вопросе: Как мне выполнить "break " или" продолжить" когда в функциональном цикле внутри Котлина?
Ответ 4
Перерыв может быть достигнут с помощью:
//Will produce"12 done with nested loop"
//Using "run" and a tag will prevent the loop from running again. Using [email protected] if I>=3 may look simpler, but it will keep running the loop and checking if i>=3 for values >=3 which is a waste of time.
fun foo() {
run [email protected]{
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) [email protected] // non-local return from the lambda passed to run
print(it)
}
}
print(" done with nested loop")
}
И продолжить можно с помощью:
//Will produce: "1245 done with implicit label"
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) [email protected] // local return to the caller of the lambda, i.e. the forEach loop
print(it)
}
print(" done with implicit label")
}
Как кто-нибудь здесь рекомендует... читать документы: Phttps://kotlinlang.org/docs/reference/returns.html#return-at-labels
Ответ 5
Как сказано в документации Kotlin, использование return
- путь к успеху. Хорошая вещь о kotlin состоит в том, что если у вас есть вложенные функции, вы можете использовать метки для подробного написания, откуда ваш возврат:
Возврат области действия функции
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")
}
и
Локальный возврат (он не прекращает проход через forEach = продолжение)
fun foo() {
listOf(1, 2, 3, 4, 5).forEach [email protected]{
if (it == 3) [email protected] // local return to the caller of the lambda, i.e. the forEach loop
print(it)
}
print(" done with explicit label")
}
Оформление документации, это действительно хорошо :)
Ответ 6
Поведение типа continue
в forEach
list.forEach { item -> // here forEach give you data item and you can use it
if () {
// your code
[email protected] // Same as continue
}
// your code
}
для поведения типа break
вы должны использовать for until
for (index in 0 until list.size) {
val item = listOfItems[index] // you can use data item now
if () {
// your code
break
}
// your code
}