Kotlin有非常好的迭代函数,如forEach或repeat,但我不能使中断和继续操作符与它们一起工作(本地和非本地):
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)
}
}
编辑:
根据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")
}
如果您想模拟中断,只需添加一个运行块
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")
}
}
最初的回答:
因为你提供了一个(Int) ->单元,你不能中断它,因为编译器不知道它是在循环中使用的。
你有几个选择:
使用常规的for循环:
for (index in 0 until times) {
// your code here
}
如果循环是方法中的最后一个代码
您可以使用return来退出方法(如果不是单元方法,则返回值)。
使用方法
创建一个自定义重复方法,该方法返回用于继续的布尔值。
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")
}
可以通过以下方式实现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
编辑:
虽然主要问题是关于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")
}
如果条件依赖于列表中前一个元素的结果,则可以使用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()来执行序列。
详情:https://kotlinlang.org/docs/sequences.html#sequence