![](/img/trans.png)
[英]Simulating `continue;`, `break;` in lambda-based foreach loops
[英]`break` and `continue` in `forEach` in Kotlin
Kotlin 具有非常好的迭代函数,例如forEach
或repeat
,但我无法使用它们进行break
和continue
运算符(本地和非本地):
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)
}
}
这将打印 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)
}
}
在Kotlin Playground尝试它们。
编辑:
根据 Kotlin 的文档,可以使用注释。
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")
}
原答案:
由于您提供了(Int) -> Unit
,您无法摆脱它,因为编译器不知道它在循环中使用。
你有几个选择:
使用常规 for 循环:
for (index in 0 until times) {
// your code here
}
如果循环是方法中的最后一个代码
您可以使用return
退出该方法(如果不是unit
方法,则return value
)。
使用方法
创建一个自定义的重复方法方法,该方法返回Boolean
以继续。
public inline fun repeatUntil(times: Int, body: (Int) -> Boolean) {
for (index in 0 until times) {
if (!body(index)) break
}
}
可以使用以下方法实现中断:
//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")
}
并且可以通过以下方式实现继续:
//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
编辑:虽然主要问题是关于 forEach,但重要的是要考虑旧的“for”。 使用 Kotlin 并不意味着我们需要一直使用 forEach。 使用旧的“for”完全没问题,有时甚至比 forEach 更具表现力和简洁性:
fun foo() {
for(x in listOf(1, 2, 3, 4, 5){
if (it == 3) break//or continue
print(it)
}
}
print("done with the good old for")
}
您可以使用lambda 表达式的 return ,它根据您的使用情况模拟continue
或break
。
这在相关问题中有所涉及: 在 Kotlin 中的功能循环中,如何进行“中断”或“继续”?
正如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")
}
和本地返回(它不会停止通过 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")
}
查看文档,它真的很好:)
在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 until
或for in
根据列表为Nullable
或Non-Nullable
对于可空列表:
for (index in 0 until list.size) { val item = list[index] // you can use data item now if () { // your code break } // your code }
对于不可空列表:
for (item in list) { // data item will available right away if () { // your code break } // your code }
我有一个完美的解决方案(:
list.apply{ forEach{ item ->
if (willContinue(item)) return@forEach
if (willBreak(item)) return@apply
}}
嵌套循环 forEach() 的 Break 语句:
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
使用匿名函数继续语句:
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
}
}
它适用于哈希图
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
这里写while
。
如https://medium.com/@windmaomao/kotlin-day-1-up-and-down-38885a5fc2b1 的第 2 部分
如果条件取决于列表中前一个元素的结果,则可以使用sequence
和takeWhile
延迟执行深度优先。
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()
来执行序列。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.