Kotlinで機能ループを中断または継続する
1. イントロ
breakおよびcontinueキーワードを使用して、Kotlin の機能ループからジャンプすることはできません。少なくとも、従来の方法ではできません。
たとえば、 break ステートメントを記述するだけでは、forEach機能ループの実行を停止することはできません。
ただし、その動作を模倣するために使用できる手法があります。 それらのいくつかを見てみましょう。
2. ラベルの使用
ご存知のとおり、ラベルを使用してreturnステートメントを修飾できます。 これを使用して、機能ループでの従来の‘continue’および‘break’の動作をシミュレートできます。
2.1. 続行のシミュレーション
例を見てみましょう:
val list = listOf(3, 4, 3, 4, 3)
var sum = 0
list.forEach loop@{ number ->
if (number % 2 == 0) { // skip all even numbers
return@loop
}
sum += number
}
assertTrue { sum == 9 }
ここ、
特定の反復の実行をスキップするには、機能ループが必要です。 これを行うには、‘loop’ラベルをreturn @loopステートメントとともに使用します。
2.2. ブレークのシミュレーション
同様に、ラベルと return ステートメントを使用して、‘break’をシミュレートすることもできます。
run outer@{
list.forEach inner@{ number ->
if (number % 2 == 0) { // 'break' at the first even number
return@outer
}
sum += number
}
}
assertTrue { sum == 3 }
前の例とは異なり、‘break’をシミュレートするために追加の定型文が必要です。 別のスコープ内でループを囲む必要があります。 これは、後で外部スコープに戻ることができるようにするために必要です。
明確にするために、( inner )ループラベルに戻るため、現在の反復のみをスキップするため、外部スコープを作成します。 ループ自体の実行を停止しません。
ラベルなしでreturnステートメントを使用することもできます。 その場合、関数自体を返すことになります。 これにより、ループの後に関数内の他のステートメントがスキップされる可能性があるため、追加の外部スコープが必要になります。
特に、ここではrunの代わりに他のスコープ関数を使用することもできます。
3. filterおよびtakeWhileを使用する
‘continue’および‘break’の動作を模倣する別の方法は、filterやtakeWhileなどの関数でそれらをチェーンすることです。
3.1. 続行をフィルターでシミュレート
通常のforループでcontinueを使用すると、処理したくない要素の反復をスキップできます。 filter を使用して、機能ループでこれを行うことができます。
val list = listOf(3, 4, 3, 4,
var sum = 0
list.filter { it % 2 != 0 } // skip all even numbers
.forEach { number ->
sum += number
}
assertTrue { sum == 9 }
ここで、は、 filter 操作を使用して、事前にスキップしたい要素をフィルタリングします。 次に、フィルタリングされたリストを繰り返し処理します。 これにより、通常のforループでcontinueを使用した場合と同じ結果が効果的に得られます。
3.2. breakをtakeWhileでシミュレート
同様に、その前に takeWhile を呼び出すことにより、機能ループでbreakの動作を模倣できます。
list.takeWhile { it % 2 != 0 } // 'break' at the first even number
.forEach { number ->
sum += number
}
assertTrue { sum == 3 }
ご存知のように、 takeWhileはリストをフィルタリングし、指定された述語を満たさない最初の要素に到達した後にすべての要素を削除します。 結果のリストを反復処理することにより、break。と同じ結果が得られます。
4. 結論
Kotlinの機能ループは、breakおよびcontinueジャンプをサポートしていません。 ただし、これを模倣するためにいくつかの手法を使用できます。
ラベル付きのreturnステートメントの方が効率的であるようです。 これは、中間コレクションの作成につながる可能性のある関数チェーンのオーバーヘッドによるものです。
一方、filterとtakeWhileを使用すると、必要なボイラープレートが最も少なくなるようです。
いつものように、コードサンプルはGitHubでから入手できます。