Table of Contents
Kotlin の while, for では break, continue が使えますが、forEach, repeat では使えません。
環境
- Kotlin 1.3.11
まずは、 forEach, repeat で break, continue を使いたい場合の簡単な対処方法を紹介します。 そのあとでなぜこうなっているのかを説明します。
簡単な対処方法
forEach, repeat は いずれも for で書き換えられるので、書き換えてしまえば break, continue が使えます。
| 前 | 後 | |
|---|---|---|
forEach |
something.forEach |
for (it in something) |
repeat |
repeat (time) |
for (it in time) |
なぜ break, continue が使えないのか
(現実をいってしまえば Kotlin がそう作られているからなのですが、) while, for と forEach, repeat には大きな違いがあります。
while,forは Kotlin の構文forEach,repeatは Kotlin の関数
似た記法になっているのでわかりにくくなっていますが、 while, for は構文として、 break, continue が使えるように設計されています。 一方で、 forEach, repeat は Kotlin の標準ライブラリで定められた高階関数です。
|
1 2 3 |
releat (3) { // this is function } |
つまり { ... } は関数です。
関数の中で break や continue が出てくるのは変ですね。 break, continue は使えません。
イテレーションをコントロールする他の方法
forEach, repeat などの高階関数でブロック部分を抜けるには、 return を使います。 関数ですから return で終了するのは自然に思えますね。
しかし、 return をそのまま使うと、 呼び出し元の関数を終了してしまいます。
|
1 2 3 4 5 6 7 |
fun something() { listOf(1, 2, 3).forEach { println(it) return // something を終了する } println("finish") } |
ラベルを使うとこれを簡単に制御できます。
continue のような処理
ラムダを使う場合
return@ラムダのラベル でラムダの continue を行うことができます。
|
1 2 3 4 5 6 7 8 |
fun something() { listOf(1, 2, 3).forEach { println(it) return@forEach // ブロック内の処理はここまで println(it) } println("finished") } |
このラベルは自分でつけることもできて ラベル名@{ ... } のように記述します。
もし forEach が2重だったら
2重で forEach がある場合は、ラベルを自分でつけます。 次のコードは外側のループに対して continue を行なっています。
|
1 2 3 4 5 6 7 8 9 10 |
fun something() { listOf(1, 2, 3).forEach outer@{ a -> listOf(4, 5, 6).forEach { b -> print(a) return@outer println(b) } } println("finished") } |
無名関数を使う場合
ラムダを無名関数に変えれば、 単純に return と書くだけで同じことができます。
|
1 2 3 4 5 6 7 |
fun something() { listOf(1, 2, 3).forEach(fun(value: Int) { println(value) return // ブロック内の処理はここまで println(it) }) } |
break のような処理
continue と同じようにラベルを使うのですが、 外側にスコープ関数をつけます。
ラムダを使う場合
外側をスコープ関数の run で囲んで、 そのラムダを抜けるように return@run と記述します
|
1 2 3 4 5 6 7 8 9 10 |
fun something() { run { listOf(1, 2, 3).forEach { println(it) return@run // ループはここでおわり println(it) } } println("finished") } |
見てわかるように、 ラムダは break を前提に作られていません。
無名関数を使う場合
ラムダの場合と同じようにラベルを使います。
|
1 2 3 4 5 6 7 8 9 |
fun something() { var breakFlag = false listOf(1, 2, 3).forEach(fun(value) { println(value) return@run // ループはここでおわり println(value) }); println("finished") } |
break, continue のまとめ
上記をまとめると次のようになります。
| break | continue | |
| ラムダ | スコープ関数とラベル | ラベル |
|---|---|---|
| 無名関数 | return |


