Edit Page

returnとジャンプ

Kotlinには3つの構造的ジャンプ演算子があります。

  • return はデフォルトではそれを包む最も近い関数または無名関数から抜け出します。
  • break はそれを包む最も近いループを終わらせます。
  • continue はそれを包む最も近いループを、次のステップに進めます。

これらはすべて、より大きな式の一部として使う事が出来ます:

val s = person.name ?: return

これらの式の型はNothing型です。

breakとcontinueのラベル

Kotlinにおける任意の式を labelでマークすることができます。ラベルは、識別子の後ろに@ 記号が続く形式です。 例えばabc@fooBar@など。 式にラベルを付けるには、式の前にラベルを置きましょう:

loop@ for (i in 1..100) {
  // ...
}

さあ、これで私たちは breakcontinue をラベル付きで出来るようになりました:

loop@ for (i in 1..100) {
  for (j in 1..100) {
        if (...) break@loop
  }
}

ラベル付き break はそのラベルが付いたループのすぐ後の実行ポイントへジャンプします。 continue はそのループの次の繰り返し実行(イテレーション)まで進みます。

ラベルにreturnする

Kotlinでは、関数リテラル、ローカル変数、object式を使用すると、関数を入れ子にすることができます。 ラベル付きの returnを使うと、外側の関数からreturnすることができます。 最も重要なユースケースは、ラムダ式からのreturnです。 以下のように書くと、return式は最も近いそれを包んでいる関数、つまりfooからreturnする事を思い出してください:

//sampleStart fun foo() { listOf(1, 2, 3, 4, 5).forEach { if (it == 3) return // non-local return はfoo()の呼び出し元に直接帰ってしまう print(it) } println("この地点には来ません") } //sampleEnd fun main() { foo() }

このようなnon-local なreturnはインライン関数に渡されたラムダ式でのみサポートされていることに注意してください。 もしラムダ式からだけ復帰する必要がある場合は、そのラムダ式にラベルを付け、 return をラベルで修飾する必要があります:

//sampleStart fun foo() { listOf(1, 2, 3, 4, 5).forEach lit@{ if (it == 3) return@lit // ラムダの呼び出し元、つまりforEachループにreturnするlocal return print(it) } print("明示的なラベル指定あり") } //sampleEnd fun main() { foo() }

上の例は、(二つ前の例と異なり)ラムダ式からのみ復帰しています。

多くの場合、暗黙のラベル(implicit labels)を使用する方が便利です。 そのようなラベルは、ラムダが渡された関数と同じ名前を持っています。

//sampleStart fun foo() { listOf(1, 2, 3, 4, 5).forEach { if (it == 3) return@forEach // ラムダの呼び出し元、つまりforEachループにreturnするlocal return print(it) } print("暗黙のラベル指定あり") } //sampleEnd fun main() { foo() }

代わりの手法として、ラムダ式の代わりに無名関数を使うという方法もあります。 無名関数内の return 文は、その無名関数自体から復帰します。

//sampleStart fun foo() { listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) { if (value == 3) return // 無名関数の呼び出し元、つまりforEachループにreturnする local return print(value) }) print("無名関数を使った場合") } //sampleEnd fun main() { foo() }

上記の3つのlocal returnの例は、通常のループのcontinueと似ているということに注目してください。

break相当のものは直接は存在しませんが、 外側にlambdaを足してそこからnon-localにreturnすれば同じような機能を実現出来ます:

//sampleStart fun foo() { run loop@{ listOf(1, 2, 3, 4, 5).forEach { if (it == 3) return@loop // runに渡されたラムダからのnon-localなreturn print(it) } } print(" ループのネストを使った場合") } //sampleEnd fun main() { foo() }

値を返すとき、パーサはラベル付けreturnの方を優先します。すなわち、

return@a 1

上記は「 @a ラベルからのreturn 1 」を意味し、「 ラベルが付いた式(@a 1) をreturn」ではありません。