web-dev-qa-db-ja.com

Kotlinの「forEach」で「break」と「continue」

KotlinにはforEachrepeatのような非常に素晴らしい反復関数がありますが、breakおよびcontinue演算子をそれらと連携させることはできません(ローカルおよび非ローカルの両方) ):

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)
    }
}
76
voddan

編集
Kotlinの 古いドキュメント-リンクが壊れています によると、アノテーションを使用することが可能です。ただし、まだ実装されていません。

カスタム制御構造のブレークアンドコンティニューはまだ実装されていません

この機能の issue は3年前なので、修正される予定はありません。


元の回答
(Int) -> Unitを指定するので、コンパイラーがループで使用されていることを知らないため、それを中断することはできません。

いくつかのオプションがあります:

通常のforループを使用します:

for (index in 0..times - 1) {
    // your code here
}

ループがメソッドの最後のコードである場合
returnを使用してメソッドから抜けることができます(unitメソッドでない場合はreturn value)。

メソッドを使用する
継続のためにBooleanを返すカスタム繰り返しメソッドを作成します。

public inline fun repeatUntil(times: Int, body: (Int) -> Boolean) {
    for (index in 0..times - 1) {
        if (!body(index)) break
    }
}
31
Yoav Sternberg

これは1〜5を出力します。return@forEachはJavaのキーワードcontinueと同様に機能します。つまり、この場合、すべてのループを実行しますが、値が5より大きい場合は次の反復にスキップします。

fun main(args: Array<String>) {
    val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    nums.forEach {
       if (it > 5) return@forEach
       println(it)
    }
}

これは1〜10を印刷しますが、5はスキップします。

fun main(args: Array<String>) {
    val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    nums.forEach {
       if (it == 5) return@forEach
       println(it)
    }
}

Kotlin Playground で試してください。

68
s-hunter

ラムダ式からの戻り を使用できます。これは、使用状況に応じてcontinueまたはbreakを模倣します。

これは関連する質問でカバーされています: Kotlin内の機能ループで「ブレーク」または「継続」を行う方法

26
Jayson Minard

Kotlinのドキュメントによると のように、returnを使用する方法があります。 kotlinの良い点は、関数をネストしている場合、ラベルを使用して、戻り元を明示的に記述することができることです。

関数スコープ戻り値

fun foo() {
  listOf(1, 2, 3, 4, 5).forEach {
    if (it == 3) return // non-local return directly to the caller of foo()
    print(it)
  }
  println("this point is unreachable")
}

andLocal Return(forEach =継続を通過するのを止めない)

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

ドキュメントをチェックしてください、本当に良いです:)

14
cesards

ブレークは以下を使用して達成できます。

//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")
}

そして、継続は次のようにして達成できます。

//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

13
Raymond Arteaga

continueforEachのタイプの動作

list.forEach { item -> // here forEach give you data item and you can use it 
    if () {
        // your code
        return@forEach // Same as continue
    }

    // your code
}

break型の動作には、for untilを使用する必要があります

for (index in 0 until list.size) {
    val item = listOfItems[index] // you can use data item now
    if () {
        // your code
        break
    }

    // your code
}
1
Sumit Jain