Kotlin | 在for、forEach循环中正确的使用break、continue-灵析社区

IT大鲨鱼

Kotlin 有三种结构化跳转表达式:

· return:默认从最直接包围它的函数或者匿名函数返回。

· break:终止最直接包围它的循环。

· continue:继续下一次最直接包围它的循环。

for循环中使用break、continue

 for (i in 1..5) {    if (i == 3) break //1 这里分别使用break continue return    println("i: $i") } println("循环外继续执行")

1处分别使用break、continue、return 替换,执行结果如下:

//break i: 1i: 2循环外继续执行//continuei: 1i: 2i: 4i: 5循环外继续执行//returni: 1i: 2

嗯,跟Java中的使用姿势是一样的,继续往下看。

Label标签

在 Kotlin 中任何表达式都可以用标签(label)来标记。 标签的格式为标识符后跟 @ 符号,例如:abc@、loop@都是有效的标签。 要为一个表达式加标签,我们只要在其前加标签即可。示例:

loop@ for (i in 1..5){ //...}

这里在嵌套for循环中使用Label,可以控制break及continue的范围:

loop@ for (i in 1..2) {    println("i: $i")    for (j in 1..5) {        if (j == 3) break@loop //break continue        println("j: $j")    }}println("循环外继续执行")

执行结果:

//breaki: 1j: 1j: 2循环外继续执行//continuei: 1j: 1j: 2i: 2j: 1j: 2循环外继续执行

结论:Label标签限制的 break 跳转到刚好位于该标签指定的循环后面的执行点。 continue 继续标签指定的循环的下一次迭代

注意不能在上述代码中使用return@loop,因为目标标签表示的不是函数,错误信息如下:

Target label does not denote a function

forEach中模拟break、continue

在forEach中并不能直接使用break、continue:

可以看到直接报错了,错误信息也很明确:break 和 continue 只允许在循环中使用,而这里是forEach的闭包,所以并不能直接使用break 和 continue。那么如何在forEach中分别模拟出break、continue的效果呢?通过Label即可实现,如:

fun forEachControl() {    listOf(1, 2, 3, 4, 5).forEach forEach@{        if (it == 3) return@forEach        println("it:$it")    }    println("循环外继续执行")}

return 只会从 lambda 表达式中返回。通常情况下使用隐式标签更方便(Label 标签与接受该 lambda 的函数同名即可使用隐式标签),简化之后:

fun forEachControl() {    listOf(1, 2, 3, 4, 5).forEach{        if (it == 3) return@forEach        println("it:$it")    }    println("循环外继续执行")}

代码执行结果:

it:1it:2it:4it:5循环外继续执行

可以看到return@forEach相当于表达式里面的continue了。嗯哼?为什么不是break的效果呢?明明已经return@forEach了呀,其实这是Kotlin闭包带来的副作用,看下forEach的源码:

public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {    //注意看下面这行代码的逻辑    for (element in this) action(element)}

action函数作为参数传入的,所以在forEach中 return@forEach 只能停止当前闭包的逻辑,后面的循环并不会受影响,会继续后面的循环。那么如何在forEach中模拟break的效果呢?只要把声明Label放到forEach外面即可以了

fun forEachControl() {    run loop@{//1       listOf(1, 2, 3, 4, 5).forEach {          if (it == 3) return@loop//2          println("it:$it")        }          println("循环外继续执行")        }    }
it:1it:2

可以看到1处的Label标签放到了forEach的外层了,那么当执行2处的return@loop时会直接跳出forEach循环,进而实现了break功能。

阅读量:873

点赞量:0

收藏量:0