2016-01-06 5 views
23

Kotlinでは、関数ループ内でbreakまたはcontinueを実行することはできません。通常のforループからは私のラムダ様ができます。Kotlin内の機能ループで「中断」または「続行」を行うにはどうすればよいですか?

(1..5).forEach { 
    [email protected] // not allowed, nor [email protected] 
} 

が、これが利用可能であることに言及old documentationがあるが、それは実現しませんでした表示されます。たとえば、これは動作しません。ラムダ内からcontinueまたはbreakにしたいときに、同じ動作をさせるための最良の方法は何ですか?

注:慣用的な答えは、一般的に尋ねすることKotlinのトピックがSOに存在しているように、この質問は、意図的に、作者(Self-Answered Questions)によって書かれ、答えています。また、現行のKotlinでは正確ではない、Kotlinのalphasのために書かれた、本当に古い答えを明らかにする。

答えて

40

使用方法によっては、continueまたはbreakを模倣するreturn from lambda expressionを使用できます。ここで

continueを模倣する例です。

(1..5).forEach { 
    if (it == 3) [email protected] // mimic [email protected] 
    // ... do something more 
} 

そして、あなたはより複雑行くとあなたが営巣や混乱状況に持ったときにラベルを使用することができます:あなたがしたい場合は

(1..3).forEach [email protected] { x -> 
    (1..3).forEach [email protected] { y -> 
     if (x == 2 && y == 2) [email protected] // mimic [email protected] 
     if (x == 1 && y == 1) [email protected] // mimic [email protected] 
     // ... do something more 
    } 
} 

breakループの外で返すことができるものが必要な場合は、ここでrun()関数を使用して:

run [email protected] { 
    (1..20).forEach { x -> 
     if (x == 5) [email protected] // mimic [email protected] 
     // ... do something more 
    } 
} 

代わりのrun()それは当然あなたがから壊したい場所ですforEachを取り巻くいるlet()またはapply()か何かである可能性があります。しかし、forEachの後に同じブロック内のコードをスキップするので注意してください。

これらはインライン化された関数なので、本当にオーバーヘッドを追加することはありません。

匿名機能を含むすべての特別なケースについては、Returns and JumpsのKotlinリファレンスドキュメントをお読みください。ここで


すべての作品にこれを証明するユニットテスト:ブレークと

@Test fun testSo32540947() { 
    val results = arrayListOf<Pair<Int,Int>>() 
    (1..3).forEach [email protected] { x -> 
     (1..3).forEach [email protected] { y -> 
      if (x == 2 && y == 2) [email protected] // continue @outer 
      if (x == 1 && y == 1) [email protected] // 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 [email protected] { 
     (1..20).forEach { x -> 
      if (x == 5) [email protected] 
      results2.add(x) 
     } 
    } 

    assertEquals(listOf(1,2,3,4), results2) 
} 
+0

は美しく、別の解決策ではありませんか? – store88

1

forEachがspecificly anyfunctionで置換することができます。

(1..20).any { x -> 
    (x == 5).apply { // break on true 
     if (!this) { 
      results2.add(x) 
     } 
    } 
} 

または可能性さえ短い:

(1..20).any { x -> 
    results2.add(x) 
    x == 4 // break on true 
} 
+1

唯一の問題は、trueを返すラムダの最初の呼び出しで停止すると文書化されておらず、それほど明白でないことです。あなたがコードにコメントを書いていないのであれば、ロジックを見逃す人は何人ですか? –

0

takeWhile breakの代わりにstdlib関数を使用できます。例えば

val array = arrayOf(2, 8, 4, 5, 13, 12, 16) 
array.takeWhile { it % 2 == 0 }.forEach { println(it) } // break on odd 
array.takeWhile { it % 3 != 0 }.forEach { println(it) } // break on 3 * n 
+0

使用例はあなたの答えを改善します。 –

+1

これは、すべての満足する要素を新しく割り当てられた中間コレクションにコピーすることに注意してください。 – Vadzim

関連する問題