1. 概要

関数は、Kotlinの一級市民です。 ラムダ式の一部としてローカル関数または関数リテラルを宣言することができます。 その結果、多くの状況で他の関数内の関数になってしまう可能性があります。

このクイックチュートリアルでは、このような入れ子関数構造で特定の関数から戻る方法を説明します。

2. ラベルに戻る

デフォルトでは、Kotlinのreturn式は最も近い囲み関数から戻ります。 例えば:

fun <T> List<T>.findOne(x: T): Int {
    forEachIndexed { i, v ->
        if (v == x) {
            return i
        }
    }

    return -1;
}

上記の例では、 returni式はfindOne関数の呼び出し元に戻ります。

ただし、場合によっては、囲んでいる関数ではなく、ラムダ式から戻る必要があります。 そのためには、 return@label構文を使用できます。 デフォルトでは、 ラベルラムダを受け入れる関数の名前です– forEachIndexed この場合:

fun <T> List<T>.printIndexOf(x: T) {
    forEachIndexed { i, v ->
        if (v == x) {
            print("Found $v at $i")
            return@forEachIndexed // return out of the lambda
        }
    }
}

このアプローチは、修飾されたリターン、ラベルでのリターン、またはreturn@としても知られています。 printIndexOf()呼び出し元に戻る代わりに、“ return @ forEachIndexed” はラムダ式からのみ戻り、囲んでいる関数の実行を続行します。

関数名の代わりにカスタムラベルを使用することもできます。

fun <T> List<T>.printIndexOf2(x: T) {
    forEachIndexed loop@{ i, v ->
        if (v == x) {
            print("Found $v at $i")
            return@loop
        }
    }
}

上記のように、デフォルトのラベルの名前をloopに変更しました。 そのためには、ラムダ式の開き括弧の前にlabel@を付ける必要があります。

興味深いことに、このアプローチは、ネストされたラムダ関数のレベルが複数ある場合でも機能します。

fun <T> List<List<T>>.nestedFind(x: T) {
    forEach { 
        it.forEachIndexed { i, v -> 
            if (v == x) {
                println("Found $v at $i")
                return@forEach
            }
        }
    }
}

上に示したように、 return @ forEach は、外側のforEach関数から戻ります。

最後に、ラムダ式を無名関数に置き換えることで、標準のreturn式を使用できます。

fun <T> List<T>.printIndexOfAnonymous(x: T) {
    forEachIndexed(fun(i: Int, v: T) {
        if (v == x) {
            print("Found $v at $i")
            return
        }
    })
}

このように、最も近い囲み関数は無名関数になるため、修飾されたreturnは必要ありません。

3. 結論

この短いチュートリアルでは、Kotlinのネストされた関数構造でreturn式の動作を制御する方法を説明しました。

いつものように、すべての例はGitHubから入手できます。