Kotlin中的' forEach '中的' break '和' continue '

Kotlin有非常好的迭代函数,如forEachrepeat,但我不能让breakcontinue操作符与它们一起工作(本地和非本地):

repeat(5) {
break
}


(1..5).forEach {
continue@forEach
}

我们的目标是用函数式语法尽可能地模拟通常的循环。在一些旧版本的Kotlin中,这是绝对可能的,但是我很难重现语法。

问题可能是标签的错误(M12),但我认为第一个示例应该工作。

我好像在什么地方读到过一个特殊的技巧/注释,但我找不到任何关于这个主题的参考资料。可能看起来像下面这样:

public inline fun repeat(times: Int, @loop body: (Int) -> Unit) {
for (index in 0..times - 1) {
body(index)
}
}
177973 次浏览
< p > 编辑:
根据Kotlin的文档,可以使用注释来模拟continue
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")
}

如果你想模拟break,只需要添加一个run

fun foo() {
run lit@ {
listOf(1, 2, 3, 4, 5).forEach {
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")
}
}

< p > 原来的答案:
因为你提供了一个(Int) -> Unit,你不能中断它,因为编译器不知道它是在循环中使用的

你有几个选择:

使用常规的for循环:

for (index in 0 until times) {
// your code here
}
< p > 如果循环是方法中的最后一个代码
你可以使用return来退出方法(如果不是unit方法,则使用return value) < p > 使用方法
创建一个自定义的重复方法,返回Boolean用于继续
public inline fun repeatUntil(times: Int, body: (Int) -> Boolean) {
for (index in 0 until times) {
if (!body(index)) break
}
}

你可以使用从lambda表达式返回,它模仿continuebreak,这取决于你的用法。

这在相关问题我怎么做一个“break”?或“;continue"在Kotlin的函数循环中?中涵盖

这将输出1到5。return@forEach的作用类似于Java中的关键字continue,这意味着在这种情况下,它仍然执行每个循环,但如果值大于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)
}
}

这将打印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)
}
}

这将输出1到4,当达到5时中断。

fun main(args: Array<String>) {
val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    

run breaking@ {
nums.forEach {
if (it == 5) return@breaking
println(it)
}
}
}

链接到ashuges的代码片段

作为Kotlin文档说,使用return是正确的方法。Kotlin的好处是,如果你有嵌套函数,你可以使用标签显式地写你的return来自哪里:

函数范围
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
/** Non-local return directly to the caller of foo(). */
if (it == 3) return
print(it)
}


println("this point is unreachable")
}
当地的回报

它不会停止执行forEach循环(它就像for循环中的continue)。

fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
/** Local return to the caller of the lambda, i.e. the forEach loop. */
if (it == 3) return@lit
print(it)
}


print(" done with explicit label")
}

看看文档,它真的很好:)

可以使用以下方法实现中断:

//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")
}

可以通过以下方式实现continue:

//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")
}

正如在座各位所推荐的…阅读文档:P https://kotlinlang.org/docs/reference/returns.html#return-at-labels < / p >

<强>编辑: 虽然主要问题是关于forEach的,但重要的是要考虑好旧的“for”。使用Kotlin并不意味着我们需要一直使用forEach。使用古老的“for”;是完全可以的,有时甚至比forEach更有表现力和简洁:

fun foo() {
for(x in listOf(1, 2, 3, 4, 5){
if (x == 3) break //or continue
print(x)
}
print("done with the good old for")
}

forEach中的continue类型行为

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


// your code
}

对于break类型的行为,你必须使用for in untilfor in,因为列表是NullableNon-Nullable

  1. 对于可以为空列表:

    for (index in 0 until list.size) {
    val item = list[index] // you can use data item now
    if () {
    // your code
    break
    }
    
    
    // your code
    }
    
  2. For Non-Nullable list:

    for (item in list) { // data item will available right away
    if () {
    // your code
    break
    }
    
    
    // your code
    }
    

forEach():

listOf("a", "b", "c").forEach find@{ i ->
listOf("b", "d").forEach { j ->
if (i == j) return@find
println("i = $i, j = $j")
}
}

结果:

i = a, j = b
i = a, j = d
i = c, j = b
i = c, j = d

带有匿名函数的Continue语句:

listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
if (value == 3) return
print("$value ")
})

结果:

1 2 4 5

也许可以将forEach改为这样:

for (it in myList) {
if (condition) {
doSomething()
} else {
break // or continue
}
}

它适用于HashMap:

 for (it in myMap) {
val k = it.key
val v = it.value


if (condition) {
doSomething()
} else {
break // or continue
}
}
fun part2(ops: List<Int>): Int = ops.asSequence()
.scan(0) { acc, v -> acc + v }
.indexOf(-1)

如果你能负担得起将一个集合转换为sequence,通常成本是微不足道的,那么你应该能够利用延迟特性。

你可能已经注意到上面的asSequence。这是为了让我们不去看整个名单。在通过indexOf进行匹配之后,它将停止。宾果!节省我们在这里写一个while

中文章的第2部分。

我有一个完美的解决方案(:

list.apply{ forEach{ item ->
if (willContinue(item)) return@forEach
if (willBreak(item)) return@apply
}}

如果条件依赖于列表中前一个元素的结果,则可以使用sequencetakeWhile来延迟执行深度优先。

sequenceOf(1, 2, 3, 4, 5).map { i ->
println("i = ${i}")
i < 3
}.takeWhile { success ->
println("success = ${success}")
success
}.toList()

将打印

i = 1
success = true
i = 2
success = true
i = 3
success = false

最后需要终端toList()来执行该序列。

更多详细信息:https://kotlinlang.org/docs/sequences.html#sequence