在 Kotlin 的函数循环中如何执行 "break" 或 "continue"?
How do I do a "break" or "continue" when in a functional loop within Kotlin?
在 Kotlin 中,我不能在函数循环和我的 lambda 中执行 break
或 continue
—— 就像我可以在正常的 for
循环中那样。例如,这不起作用:
(1..5).forEach {
continue@forEach // not allowed, nor break@forEach
}
有 old documentation 提到此功能可用,但似乎从未实施过。当我想从 lambda 中 continue
或 break
时,获得相同行为的最佳方法是什么?
注意: 此问题是作者(Self-Answered Questions)特意写下并回答的,以便对常见的 Kotlin 主题进行地道的回答存在于 SO 中。还要澄清一些为 Kotlin alpha 编写的非常古老的答案,这些答案对于当今的 Kotlin 来说并不准确。
除您要求的选项外,还有其他提供类似功能的选项。例如:
您可以使用 filter
避免处理某些值:(如 continue
)
dataSet.filter { it % 2 == 0 }.forEach {
// do work on even numbers
}
您可以使用 takeWhile
停止功能循环:(就像 break
)
dataSet.takeWhile { it < 10 }.forEach {
// do work on numbers as long as they are < 10, otherwise stop
}
一个更复杂但无意义的示例,您想要进行一些处理,跳过一些结果值,然后在一组不同的条件下停止,将是:
dataSet.asSequence()
.takeWhile { it >= 0 } // a -1 signals end of the dataset (break)
.map { it + 1 } // increment each number
.filterNot { it % 5 == 0 } // skip (continue) numbers divisible by 5
.map { it - 1 } // decrement each number by 1
.filter { it < 100 } // skip (continue) if number is >= 100
.drop(5) // ignore the first 5 numbers
.take(10) // use the next 10 numbers and end
.forEach {
// do work on the final list
}
这些功能的组合往往会消除 continue
或 break
的需要。这里有无穷无尽的不同选择,而且比可以记录的还要多。要了解可以做什么,最好了解 collections, lazy sequences, and iterable.
的 Kotlin 标准库中可用的所有函数。
有时,您的变异状态仍然需要 break
或 continue
,但在功能模型中很难做到。您可以使用更复杂的函数(例如 fold
和 reduce
结合 filter
和 takeWhile
函数来使其工作,但有时这更难理解。因此,如果您真的想要那种确切的行为,您可以使用 return from lambda expression 来模仿 continue
或 break
,具体取决于您的用法。
这是一个模仿 continue
:
的例子
(1..5).forEach {
if (it == 3) return@forEach // mimic continue@forEach
// ... do something more
}
当你遇到嵌套或混淆的情况时,你可以变得更复杂并使用标签:
(1..3).forEach outer@ { x ->
(1..3).forEach inner@ { y ->
if (x == 2 && y == 2) return@outer // mimic continue@outer
if (x == 1 && y == 1) return@inner // mimic continue@inner
// ... do something more
}
}
如果你想做一个 break
你需要在循环之外的东西,你可以 return 从这里我们将使用 run()
函数来帮助我们:
run breaker@ {
(1..20).forEach { x ->
if (x == 5) return@breaker // mimic break@forEach
// ... do something more
}
}
而不是 run()
,它可以是 let()
或 apply()
或您想要突破的 forEach
周围自然存在的任何东西。但是您也会跳过 forEach
之后同一块中的代码,所以要小心。
这些是内联函数,因此实际上它们并没有真正增加开销。
阅读 Kotlin 参考文档 Returns and Jumps 了解所有特殊情况,包括匿名函数。
这是一个单元测试证明这一切有效:
@Test fun testSo32540947() {
val results = arrayListOf<Pair<Int,Int>>()
(1..3).forEach outer@ { x ->
(1..3).forEach inner@ { y ->
if (x == 2 && y == 2) return@outer // continue @outer
if (x == 1 && y == 1) return@inner // continue @inner
results.add(Pair(x,y))
}
}
assertEquals(listOf(Pair(1,2), Pair(1,3), Pair(2,1), Pair(3,1), Pair(3,2), Pair(3,3)), results)
val results2 = arrayListOf<Int>()
run breaker@ {
(1..20).forEach { x ->
if (x == 5) return@breaker
results2.add(x)
}
}
assertEquals(listOf(1,2,3,4), results2)
}
forEach
with break 可以具体替换为 any function:
(1..20).any { x ->
(x == 5).apply { // break on true
if (!this) {
results2.add(x)
}
}
}
或者可能更短:
(1..20).any { x ->
results2.add(x)
x == 4 // break on true
}
takeWhile 可以使用 stdlib 函数代替 break。
例如,
val array = arrayOf(2, 8, 4, 5, 13, 12, 16)
array.takeWhile { it % 2 == 0 }.forEach { println(it) } // break on odd
array.takeWhile { it % 3 != 0 }.forEach { println(it) } // break on 3 * n
在 Kotlin 中,我不能在函数循环和我的 lambda 中执行 break
或 continue
—— 就像我可以在正常的 for
循环中那样。例如,这不起作用:
(1..5).forEach {
continue@forEach // not allowed, nor break@forEach
}
有 old documentation 提到此功能可用,但似乎从未实施过。当我想从 lambda 中 continue
或 break
时,获得相同行为的最佳方法是什么?
注意: 此问题是作者(Self-Answered Questions)特意写下并回答的,以便对常见的 Kotlin 主题进行地道的回答存在于 SO 中。还要澄清一些为 Kotlin alpha 编写的非常古老的答案,这些答案对于当今的 Kotlin 来说并不准确。
除您要求的选项外,还有其他提供类似功能的选项。例如:
您可以使用 filter
避免处理某些值:(如 continue
)
dataSet.filter { it % 2 == 0 }.forEach {
// do work on even numbers
}
您可以使用 takeWhile
停止功能循环:(就像 break
)
dataSet.takeWhile { it < 10 }.forEach {
// do work on numbers as long as they are < 10, otherwise stop
}
一个更复杂但无意义的示例,您想要进行一些处理,跳过一些结果值,然后在一组不同的条件下停止,将是:
dataSet.asSequence()
.takeWhile { it >= 0 } // a -1 signals end of the dataset (break)
.map { it + 1 } // increment each number
.filterNot { it % 5 == 0 } // skip (continue) numbers divisible by 5
.map { it - 1 } // decrement each number by 1
.filter { it < 100 } // skip (continue) if number is >= 100
.drop(5) // ignore the first 5 numbers
.take(10) // use the next 10 numbers and end
.forEach {
// do work on the final list
}
这些功能的组合往往会消除 continue
或 break
的需要。这里有无穷无尽的不同选择,而且比可以记录的还要多。要了解可以做什么,最好了解 collections, lazy sequences, and iterable.
有时,您的变异状态仍然需要 break
或 continue
,但在功能模型中很难做到。您可以使用更复杂的函数(例如 fold
和 reduce
结合 filter
和 takeWhile
函数来使其工作,但有时这更难理解。因此,如果您真的想要那种确切的行为,您可以使用 return from lambda expression 来模仿 continue
或 break
,具体取决于您的用法。
这是一个模仿 continue
:
(1..5).forEach {
if (it == 3) return@forEach // mimic continue@forEach
// ... do something more
}
当你遇到嵌套或混淆的情况时,你可以变得更复杂并使用标签:
(1..3).forEach outer@ { x ->
(1..3).forEach inner@ { y ->
if (x == 2 && y == 2) return@outer // mimic continue@outer
if (x == 1 && y == 1) return@inner // mimic continue@inner
// ... do something more
}
}
如果你想做一个 break
你需要在循环之外的东西,你可以 return 从这里我们将使用 run()
函数来帮助我们:
run breaker@ {
(1..20).forEach { x ->
if (x == 5) return@breaker // mimic break@forEach
// ... do something more
}
}
而不是 run()
,它可以是 let()
或 apply()
或您想要突破的 forEach
周围自然存在的任何东西。但是您也会跳过 forEach
之后同一块中的代码,所以要小心。
这些是内联函数,因此实际上它们并没有真正增加开销。
阅读 Kotlin 参考文档 Returns and Jumps 了解所有特殊情况,包括匿名函数。
这是一个单元测试证明这一切有效:
@Test fun testSo32540947() {
val results = arrayListOf<Pair<Int,Int>>()
(1..3).forEach outer@ { x ->
(1..3).forEach inner@ { y ->
if (x == 2 && y == 2) return@outer // continue @outer
if (x == 1 && y == 1) return@inner // continue @inner
results.add(Pair(x,y))
}
}
assertEquals(listOf(Pair(1,2), Pair(1,3), Pair(2,1), Pair(3,1), Pair(3,2), Pair(3,3)), results)
val results2 = arrayListOf<Int>()
run breaker@ {
(1..20).forEach { x ->
if (x == 5) return@breaker
results2.add(x)
}
}
assertEquals(listOf(1,2,3,4), results2)
}
forEach
with break 可以具体替换为 any function:
(1..20).any { x ->
(x == 5).apply { // break on true
if (!this) {
results2.add(x)
}
}
}
或者可能更短:
(1..20).any { x ->
results2.add(x)
x == 4 // break on true
}
takeWhile 可以使用 stdlib 函数代替 break。
例如,
val array = arrayOf(2, 8, 4, 5, 13, 12, 16)
array.takeWhile { it % 2 == 0 }.forEach { println(it) } // break on odd
array.takeWhile { it % 3 != 0 }.forEach { println(it) } // break on 3 * n