戻りとジャンプ
Kotlinには、3つの構造化されたジャンプ式があります。
return
は、デフォルトでは最も近い囲み関数または匿名関数から戻ります。break
は、最も近い囲みループを終了します。continue
は、最も近い囲みループの次のステップに進みます。
これらの式はすべて、より大きな式の一部として使用できます。
val s = person.name ?: return
これらの式の型はNothing型です。
ラベル付きbreakとcontinue
Kotlinのあらゆる式には、ラベルを付けることができます。 ラベルは、abc@
やfooBar@
のように、識別子の後に@
記号が続く形式を持ちます。 式にラベルを付けるには、その式の前にラベルを追加するだけです。
loop@ for (i in 1..100) {
// ...
}
これで、break
またはcontinue
をラベルで修飾できます。
loop@ for (i in 1..100) {
for (j in 1..100) {
if (...) break@loop
}
}
ラベルで修飾されたbreak
は、そのラベルが付けられたループの直後の実行ポイントにジャンプします。 continue
は、そのループの次のイテレーションに進みます。
場合によっては、明示的にラベルを定義することなく、
break
やcontinue
を非ローカルに適用できます。 このような非ローカルな使用法は、囲みインライン関数内で使用されるラムダ式で有効です。
ラベル付きreturn
Kotlinでは、関数リテラル、ローカル関数、オブジェクト式を使用して関数をネストできます。 修飾されたreturn
を使用すると、外側の関数から戻ることができます。
最も重要なユースケースは、ラムダ式からの戻りです。ラムダ式から戻るには、 それにラベルを付け、return
を修飾します。
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit // ラムダの呼び出し元(forEachループ)へのローカルリターン
print(it)
}
print(" done with explicit label")
}
fun main() {
foo()
}
これで、ラムダ式からのみ戻ります。多くの場合、_暗黙的なラベル_を使用する方が便利です。なぜなら、そのようなラベルは、ラムダが渡される関数と同じ名前を持つためです。
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@forEach // ラムダの呼び出し元(forEachループ)へのローカルリターン
print(it)
}
print(" done with implicit label")
}
//end
fun main() {
foo()
}
あるいは、ラムダ式を匿名関数に置き換えることもできます。 匿名関数内のreturn
文は、その匿名関数自体から戻ります。
fun foo() {
listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
if (value == 3) return // 匿名関数の呼び出し元(forEachループ)へのローカルリターン
print(value)
})
print(" done with anonymous function")
}
fun main() {
foo()
}
前の3つの例におけるローカルリターンの使用は、通常のループにおけるcontinue
の使用に似ていることに注意してください。
break
に直接相当するものはありませんが、外側のrun
ラムダを追加し、そこから非ローカルに戻ることでシミュレートできます。
fun foo() {
run loop@{
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@loop // runに渡されたラムダからの非ローカルリターン
print(it)
}
}
print(" done with nested loop")
}
fun main() {
foo()
}
ここでの非ローカルリターンは、ネストされたforEach()
ラムダがインライン関数として機能するため可能です。
値を戻す際、パーサーは修飾されたreturn
を優先します。
return@a 1
これは、「ラベル@a
で1
を戻す」という意味であり、「ラベル付けされた式(@a 1)
を戻す」という意味ではありません。
場合によっては、ラベルを使用せずにラムダ式から戻ることができます。このような非ローカルな戻りは、ラムダ内にありますが、囲みインライン関数を終了します。