在 Kotlin 的 `forEach` 中使用 `break` 和 `continue`

297

Kotlin拥有非常好的迭代函数,例如forEachrepeat,但我无法让breakcontinue操作符在它们上面工作(包括本地和非本地):

repeat(5) {
    break
}

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

目标是尽可能地使用函数式语法来模拟常规循环。在 Kotlin 的一些旧版本中肯定是可行的,但我很难复制这种语法。

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

我记得在某个地方读到过一个特殊的技巧/注释,但我找不到任何有关此主题的参考资料。可能看起来像以下内容:

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

1
在当前的 Kotlin 中,您确实可以模仿这个功能(在等待 continue@labelbreak@label 功能时),请参见相关问题:https://dev59.com/sVsW5IYBdhLWcg3wuZRy - Jayson Minard
1
这个问题需要澄清一下,您是在询问函数式循环中是否存在breakcontinue,还是正在寻找完全相同的替代方案。前者似乎是正确的,因为您已经拒绝了后者。 - Jayson Minard
似乎他们在Kotlin 1.3中添加了这个。 - Tigran Babajanyan
@TigranBabajanyan 哇!你有链接吗? - voddan
@voddan,不,我刚试过了,它可以运行。 - Tigran Babajanyan
12个回答

0
如果条件取决于列表中先前元素的结果,则可以使用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


0
fun part2(ops: List<Int>): Int = ops.asSequence()
    .scan(0) { acc, v -> acc + v }
    .indexOf(-1)

如果你有能力将一个集合转换成序列(sequence),通常代价微不足道,那么你应该能够利用延迟计算的特性。

你可能已经注意到上面的 asSequence。它在这里是为了帮我们避免遍历整个列表。当我们通过 indexOf 找到匹配项后,它就停止了。大功告成!这样就不需要在这里编写 while 循环了。

medium article 的第二部分。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接