loops - 在 Kotlin 中的功能循环中,如何执行 "break"或 "continue"?

在 Kotlin 中,我不能在函数循环和我的 lambda 中执行 breakcontinue ——就像我可以从普通的 for环形。例如,这不起作用:

(1..5).forEach {
    continue@forEach  // not allowed, nor break@forEach
}

有old documentation这提到这是可用的,但它似乎从未实现过。当我想从 lambda 中 continuebreak 时,获得相同行为的最佳方法是什么?

注意: 这个问题是作者有意编写和回答的 (Self-Answered Questions),因此常见的 Kotlin 主题的惯用答案出现在 SO 中。还要澄清一些为 Kotlin alpha 编写的非常古老的答案,这些答案对于当前的 Kotlin 并不准确。

最佳答案

除了您所要求的以外,还有其他选项可以提供类似的功能。例如:

您可以避免使用 filter 处理某些值: (就像一个继续)

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
       }

这些功能的组合往往会消除 continuebreak 的需要。这里有无穷无尽的不同选择,而且比可以记录的还要多。要了解可以做什么,最好了解 collections 的 Kotlin 标准库中的所有可用函数。 , 懒惰 sequences , 和 iterable .

有时在某些情况下,您的变异状态仍需要breakcontinue 并且在功能模型中很难做到。您可以使用更复杂的函数(如 foldreduce 结合 filtertakeWhile 函数使其工作,但有时这更难理解。因此,如果您真的想要那种确切的行为,您可以使用 return from lambda expression根据您的使用情况模拟 continuebreak

这是一个模仿 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 // mimic continue@outer
        if (x == 1 && y == 1) return@inner // mimic continue@inner
        // ... do something more
    }
}

如果你想做一个break,你需要在循环之外的东西,你可以从中返回,这里我们将使用run()函数来帮助我们:

run breaker@ {
    (1..20).forEach { x ->
        if (x == 5) return@breaker  // mimic break@forEach
        // ... do something more
    }
}

而不是 run() 它可以是 let()apply() 或任何自然围绕在 forEach 周围的东西 那是你想要突破的地方。但是您也会跳过 forEach 之后的同一 block 中的代码,所以要小心。

这些是内联函数,所以实际上它们并没有真正增加开销。

阅读 Returns and Jumps 的 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)
}

关于loops - 在 Kotlin 中的功能循环中,如何执行 "break"或 "continue"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34642868/

相关文章:

android - 房间持久性 : Error:Entities and Pojos must ha

android - 当列名相同时,如何表示与 Android Room 的 "many to man

enums - 如何在 Kotlin 中为枚举创建 "static"方法?

lambda - 引用 Kotlin 中特定实例的方法

android - 如何将 Kotlin 与 Proguard 一起使用

android-studio - Kotlin:为什么 Android Studio 中的大多数变量

java - 如何在 Kotlin 中组合 Intent 标志

kotlin - 警告 : Kotlin runtime JAR files in the clas

kotlin - Kotlin 协程中的挂起函数是什么意思?

kotlin - kotlin 中的 Dagger 2 静态提供程序方法