问题描述
下面代码末尾的 count
是 4。我期望是 0。为什么是 4?我怎样才能得到 0?
var count = 0;
"hello".forEach {
if(it == 'h')
{
println("Exiting the forEach loop. Count is $count");
return@forEach;
}
count++;
}
println("count is $count");
输出:
Exiting the forEach loop. Count is 0
count is 4
解决方法
return@forEach
不会退出 forEach()
本身,而是传递给它的 lambda(forEach()
的“主体”)。请注意,此 lambda 会执行多次 - 每个项目一次。通过从它返回,你实际上只跳过了一个项目,所以这类似于 continue
,而不是 break
。
要解决此问题,您可以在外部作用域中创建一个标签并返回:
var count = 0;
run loop@ {
"hello".forEach {
if(it == 'h')
{
println("Exiting the forEach loop. Count is $count");
return@loop;
}
count++;
}
}
此处描述:https://kotlinlang.org/docs/returns.html#return-at-labels
请注意,前三个示例中局部返回的使用类似于常规循环中 continue
的使用。 break
没有直接的等价物,但可以通过添加另一个嵌套 lambda 并从中非本地返回来模拟
它是 4,因为 forEach
调用传递给它的 lambda 对于字符串中的每个字符,因此代码中的 return@forEach
返回第一个元素。您可以使用 for 循环并使用 break
获得 0。
return@forEach
从 lambda 函数返回。但是 forEach
函数是一个高阶函数,它为迭代器中的每个项目重复调用 lambda。因此,当您从 lambda 返回时,您只会返回迭代器中的单个项目。这类似于在传统的 for 循环中使用 continue
。
如果要在高阶函数中完全退出迭代,则必须使用标签。当我输入这个时,我看到另一个答案已经显示了如何做到这一点,但如果不同的解释有帮助,我会留下这个。
,如果您的目标是计算 'h' 之前的字符数,您可以执行以下操作:
val numCharsBeforeH = "hello".takeWhile { it != 'h' }.length
从您的评论到 Tenfour04 的回答:
这不是很方便。为什么 Kotlin 的开发者没有创造一个“break”等价物?
这里引用了 Coding conventions 的“循环”部分:
更喜欢使用高阶函数(filter
、map
等)而不是循环。
例外:forEach
(更喜欢使用常规的 for
循环,除非
forEach
的接收者可以为空或 forEach
被用作
更长的调用链)。
在使用多个的复杂表达式之间做出选择时 高阶函数和循环,了解成本 在每种情况下正在执行的操作并保持性能 考虑因素。
确实,使用带有 for
的常规 break
循环可以满足您的预期:
var count = 0;
for (char in "hello") {
if (char == 'h') {
println("Breaking the loop. Count is $count")
break
}
count++
}
println("count is $count")
输出:
Breaking the loop. Count is 0
count is 0
除了非常简单的操作外,可能有比使用 forEach
更好的方法来完成您需要的操作。