我如何做“休息"?或“继续"什么时候在 Kotlin 的函数循环中? [英] How do I do a "break" or "continue" when in a functional loop within Kotlin?

查看:17
本文介绍了我如何做“休息"?或“继续"什么时候在 Kotlin 的函数循环中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In Kotlin, I cannot do a break or continue within a function loop and my lambda -- like I can from a normal for loop. For example, this does not work:

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

旧文档 提到了这一点可用,但似乎从未实施过.当我想从 lambda 中 continuebreak 时获得相同行为的最佳方法是什么?

There are old documentation that mentions this being available but it appears it was never implemented. What is the best way to get the same behavior when I want to continue or break from within the lambda?

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

Note: this question is intentionally written and answered by the author (Self-Answered Questions), so that the idiomatic answers to commonly asked Kotlin topics are present in SO. Also to clarify some really old answers written for alphas of Kotlin that are not accurate for current-day Kotlin.

推荐答案

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

There are other options other than what you are asking for that provide similar functionality. For example:

您可以避免使用 filter<处理某些值/code>:(就像一个continue)

You can avoid processing some values using filter: (like a continue)

dataSet.filter { it % 2 == 0 }.forEach {
    // do work on even numbers
}

您可以使用 takeWhile:(就像一个break)

You can stop a functional loop by using takeWhile: (like a break)

dataSet.takeWhile { it < 10 }.forEach {
    // do work on numbers as long as they are < 10, otherwise stop
}

一个更复杂但无意义的示例,您想要进行一些处理,跳过一些结果值,然后在一组不同的条件下停止,将是:

A more complex, although nonsensical example where you want to do some processing, skip some resulting values, and then stop at a set of different conditions, would be:

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 的需要.这里有无穷无尽的不同选择,而且可以记录的更多.要了解可以做什么,最好学习 Kotlin 标准库中用于 collections,懒惰的sequences可迭代.

A combination of these functions tends to eliminate the need for continue or break. And there are endless different options here and more than can be documented. To get an idea of what can be done, it is best if you learn all of the functions available in the Kotlin standard library for collections, lazy sequences, and iterable.

有时在某些情况下,您仍然需要 breakcontinue 并且很难在功能模型中实现变异状态.您可以使用更复杂的函数,例如 foldreduce 结合 filtertakeWhile 函数使其工作,但有时这更难理解.因此,如果你真的想要那种确切的行为,你可以使用 从 lambda 表达式返回 根据您的使用情况模仿 continuebreak.

Sometimes there are cases where you have mutating state that still needs to break or continue and is hard to do in a functional model. You can make it work using more complex functions like fold and reduce combined with the filter and takeWhile functions but sometimes that is harder to grok. Therefore if you really want that exact behavior you can use return from lambda expression which mimics a continue or break depending on your usage.

这是一个模仿continue的例子:

(1..5).forEach  {
    if (it == 3) return@forEach  // mimic continue@forEach
    // ... do something more
}

当您遇到嵌套或混淆情况时,您可以变得更复杂并使用标签:

And you can go more complicated and use labels when you having nesting or confusing situations:

(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()函数来帮助我们:

If you want to do a break you need something outside the loop that you can return from, here we will use the run() function to help us:

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

代替 run(),它可以是 let()apply() 或任何你在 forEach 周围自然拥有的东西 那是您想要突破的地方.但是您也将跳过 forEach 之后同一块内的代码,所以要小心.

Instead of run() it could be let() or apply() or anything naturally you have surrounding the forEach that is a place you want to break from. But you will also skip the code within the same block following the forEach so be careful.

这些是内联函数,因此它们实际上并没有真正增加开销.

These are inlined functions so really they do not really add overhead.

阅读 Kotlin 参考文档,了解 返回和跳转,了解所有特殊情况,包括匿名函数.

Read the Kotlin reference docs for Returns and Jumps for all the special cases including for anonymous functions.

这是一个单元测试,证明这一切正常:

@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)
}

这篇关于我如何做“休息"?或“继续"什么时候在 Kotlin 的函数循环中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆