除了你所要求的功能,还有其他选项可以提供类似的功能。例如:
你可以使用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
的需求。而且这里有无数不同的选项,超出了可以记录的范围。为了了解可以做什么,最好学习Kotlin标准库中所有可用的函数
collections, 惰性
sequences, 和
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
if (x == 1 && y == 1) return@inner
}
}
如果你想要执行一个 break
,你需要在循环外使用一个可以从中返回的东西,这里我们将使用 run()
函数来帮助我们:
run breaker@ {
(1..20).forEach { x ->
if (x == 5) return@breaker // mimic break@forEach
// ... do something more
}
}
与其使用run()
,还可以使用let()
或apply()
,或者任何你在forEach
周围自然使用的内容作为你想要中断的位置。但是你也将跳过forEach
后面同一块中的代码,所以要小心。
这些是内联函数,因此它们实际上并不会增加额外开销。
阅读Kotlin参考文档返回和跳转,了解所有特殊情况,包括匿名函数。
这里是一个单元测试,证明所有的工作都正常:
@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)
}