Kotlinのラムダでreturnする

最近、Kotlin＋Spring BootでRESTful APIを書いてます。（とは言っても片手間でやっているので遅々として進みませんが）
コード書いていて「おやっ？」って思った表題の件について取り上げてみます。

# お題とするコード

*あんまり良い例が思いつかなったので、相当違和感あるコードかもしれませんがご勘弁ください。*

以下の様なクラスのコレクションがあります。

```kotlin
data class Country(val name: String, val continent: String,  val population: Long)

val counties = listOf(
        Country("France", "Europe", 67_158_000),
        Country("Germany", "Europe", 82_349_400),
        Country("United Kingdom", "Europe", 65_648_000),
        Country("Japan", "Asia", 126_672_000),
        Country("India", "Asia", 1_324_171_354),
        Country("China", "Asia", 1_403_500_365)
)
```

リストに指定した国名が含まれているかをチェックする関数を書きます。標準関数で事足りる話ですが、あえて冗長なコードを書きます。

```kotlin
fun isContainCountry(countries: List<Country>, name: String): Boolean {
    var filtered = countries.filter { c ->
        println(c.name)
        c.name == name
    }
    println("(Country)$filtered")

    return !filtered.isEmpty()
}
```

関数を呼び出してみると以下の様な出力になります。

```
>>> println("[RESULT]${isContainCountry (counties, "Japan")}")
France
Germany
United Kingdom
Japan
India
China
(Country)[Country(name=Japan, continent=Asia, population=126672000)]
[RESULT]true
>>> println("[RESULT]${isContainCountry (counties, "United States")}")
France
Germany
United Kingdom
Japan
India
China
(Country)[]
[RESULT]false
```

# ここからが本題

~~大した話でもないのに~~前置きが長くなりましたが本題です。

前の関数から少しだけ変更します。

```kotlin
fun isContainCountryNG(countries: List<Country>, name: String): Boolean {
    var filtered = countries.filter { c ->
        println(c.name)
        return c.name == name  // returnをつける
    }
    println("(Country)$filtered")

    return !filtered.isEmpty()
}
```

これを実行すると、

```
>>> println("[RESULT]${isContainCountryNG (counties, "Japan")}")
France
[RESULT]false
```

意図したような挙動になりません。

ラムダ内のreturnは、そのラムダを呼び出した関数からのリターンを意味します。（`非ローカルリターン`と呼ぶそうです）
つまり、いきなりisContainCountryNG関数の処理が終わってしまうことになります。
このような挙動になる理由は、filter関数がインライン展開されるからです。
filterの定義を見てみると、`inline`修飾子がついています。

```
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T>
```

インライン展開されたコードを思い浮かべれば、その中のreturnにより関数からリターンされるということがイメージできます。

C#のラムダだとこういうケースではreturnがないとコンパイルエラーだったように思います。ので、ついreturnを書いてしまうこともあるかもしれません。

以下の様に書くと、この`非ローカルリターン`もしっくりくると思います。（そもそも標準関数を使えば良いという話はさておいて）

```kotlin
fun isContainCountryForEach(countries: List<Country>, name: String): Boolean {
    countries.forEach { c ->
        println(c.name)
        if (c.name == name) return true
    }

    return false
}
```

実行結果は、

```
>>> println("[RESULT]${isContainCountryForEach (counties, "Japan")}")
France
Germany
United Kingdom
Japan
[RESULT]true
```

となります。

# ローカルリターン

`非ローカルリターン`に対して`ローカルリターン`というのが当然あります。
ローカルリターンにする方法は２つあります。

## ラベル付きreturn

```kotlin
fun isContainCountryLR(countries: List<Country>, name: String): Boolean {
    var found = false
    countries.forEach { c ->
        if (c.name == name) {
            println("I found it!")
            found = true
            return@forEach  // ラベル付きリターン
        }
        println(c.name)  // returnするとこの行は実行されない
    }
    println("Exit...")

    return found
}
```

## 無名関数

```kotlin
fun isContainCountryAF(countries: List<Country>, name: String): Boolean {
    var found = false
    countries.forEach ( fun(c) {  // 無名関数
        if (c.name == name) {
            println("I found it!")
            found = true
            return
        }
        println(c.name)  // returnするとこの行は実行されない
    })
    println("Exit...")

    return found
}
```

どちらも出力結果は同じです。

```
>>> println("[RESULT]${isContainCountryLR (counties, "Japan")}")
France
Germany
United Kingdom
I found it!
India
China
Exit...
[RESULT]true
```