在科特林的`forEach`中`break`和`continue`

vod*_*dan 87 foreach lambda loops kotlin

科特林具有非常不错的迭代功能,如forEachrepeat,但我不能让breakcontinue运营商与他们(包括本地和非本地)的工作:

repeat(5) {
    break
}

(1..5).forEach {
    continue@forEach
}
Run Code Online (Sandbox Code Playgroud)

目标是模拟通常的循环,其功能语法尽可能接近.在某些旧版本的Kotlin中肯定是可能的,但我很难重现语法.

问题可能是标签的错误(M12),但我认为第一个例子应该可行.

在我看来,我已经阅读过关于特殊技巧/注释的某处,但我找不到关于这个主题的任何参考.可能如下所示:

public inline fun repeat(times: Int, @loop body: (Int) -> Unit) {
    for (index in 0..times - 1) {
        body(index)
    }
}
Run Code Online (Sandbox Code Playgroud)

s-h*_*ter 83

这将打印1到5.这些return@forEach行为类似于continueJava中的关键字,这意味着在这种情况下,它仍然执行每个循环但如果值大于5则跳到下一次迭代.

fun main(args: Array<String>) {
    val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    nums.forEach {
       if (it > 5) return@forEach
       println(it)
    }
}
Run Code Online (Sandbox Code Playgroud)

这将打印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) return@forEach
       println(it)
    }
}
Run Code Online (Sandbox Code Playgroud)

Kotlin游乐场试试吧.

  • 很好,但这仍然没有解决满足某些条件时无法提前结束 forEach 的问题。它仍然继续执行循环。 (3认同)
  • 这是一个可运行的 Kotlin Playground 片段,其中包含“继续”和“中断”示例:https://pl.kotl.in/_LAvET-wX (2认同)

Yoa*_*erg 34

编辑:
根据Kotlin的旧文档 - 链接被破坏,应该可以使用注释.但是,它尚未实施.

尚未实现自定义控件结构的中断和继续

此功能的问题是3年,所以我想它不会被修复.


原始答案:
由于你提供了一个(Int) -> Unit,你不能打破它,因为编译器不知道它是在一个循环中使用.

你有几个选择:

使用常规for循环:

for (index in 0 until times) {
    // your code here
}
Run Code Online (Sandbox Code Playgroud)

如果循环是方法中的最后一个代码,则
可以return用来退出方法(或者return value如果它不是unit方法).

使用方法
创建返回Boolean以继续的自定义重复方法方法.

public inline fun repeatUntil(times: Int, body: (Int) -> Boolean) {
    for (index in 0..times - 1) {
        if (!body(index)) break
    }
}
Run Code Online (Sandbox Code Playgroud)

  • `break` 和 `continue` 只能在循环中工作。`forEach`、`repeat` 和所有其他方法就是这样:方法而不是循环。Yoav 提出了一些替代方案,但 `break` 和 `continue` 只是不适用于方法。 (2认同)

Jay*_*ard 27

您可以使用lambda表达式返回,表达式模仿continuebreak取决于您的用法.

这在相关问题中有所涉及: 在Kotlin中的功能循环中,如何"中断"或"继续"?


Ray*_*aga 21

可以使用以下方法实现休息:

//Will produce"12 done with nested loop"
//Using "run" and a tag will prevent the loop from running again. Using return@forEach 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 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")
}
Run Code Online (Sandbox Code Playgroud)

并且可以通过以下方式实现继续:

//Will produce: "1245 done with implicit label"
fun foo() {
    listOf(1, 2, 3, 4, 5).forEach {
        if (it == 3) return@forEach // local return to the caller of the lambda, i.e. the forEach loop
        print(it)
    }
    print(" done with implicit label")
}
Run Code Online (Sandbox Code Playgroud)

正如任何人在这里建议的......阅读文档:P https://kotlinlang.org/docs/reference/returns.html#return-at-labels


ces*_*rds 15

正如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")
}
Run Code Online (Sandbox Code Playgroud)

本地回报(它不会停止通过forEach = continuation)

fun foo() {
  listOf(1, 2, 3, 4, 5).forEach lit@{
    if (it == 3) return@lit // local return to the caller of the lambda, i.e. the forEach loop
    print(it)
  }
  print(" done with explicit label")
}
Run Code Online (Sandbox Code Playgroud)

查看文档,这真的很棒:)

  • 警告:return @ lit不会停止`forEach` (2认同)
  • 致电 Return@lit 喜欢继续 (2认同)

ar3*_*6el 8

我对此有完美的解决方案(:

list.apply{ forEach{ item ->
    if (willContinue(item)) return@forEach
    if (willBreak(item)) return@apply
}}
Run Code Online (Sandbox Code Playgroud)


Sum*_*ain 5

continue 输入行为 forEach

list.forEach { item -> // here forEach give you data item and you can use it 
    if () {
        // your code
        return@forEach // Same as continue
    }

    // your code
}
Run Code Online (Sandbox Code Playgroud)

对于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
}
Run Code Online (Sandbox Code Playgroud)