1. 序章

この短いKotlinチュートリアルでは、forEachループのラムダ内のパラメータースコープを見ていきます。

まず、例で使用するデータを定義します。 次に、forEachを使用してリストを反復処理する方法を説明します。 第三に、ネストされたループでそれを使用する方法を見ていきます。

2. テストデータ

使用するデータは国のリストであり、各国には都市のリストが含まれており、都市のリストには通りのリストが含まれています。

class Country(val name : String, val cities : List<City>)

class City(val name : String, val streets : List<String>)

class World {

    val streetsOfAmsterdam = listOf("Herengracht", "Prinsengracht")
    val streetsOfBerlin = listOf("Unter den Linden","Tiergarten")
    val streetsOfMaastricht = listOf("Grote Gracht", "Vrijthof")
    val countries = listOf(
      Country("Netherlands", listOf(City("Maastricht", streetsOfMaastricht),
        City("Amsterdam", streetsOfAmsterdam))),
      Country("Germany", listOf(City("Berlin", streetsOfBerlin))))
}

3. シンプルなforEach

リスト内の各国の名前を印刷するには、次のコードを記述できます。

fun allCountriesExplicit() { 
    countries.forEach { c -> println(c.name) } 
}

上記の構文はJavaに似ています。 ただし、Kotlinでは、ラムダが1つのパラメーターのみを受け入れる場合、デフォルトのパラメーター名として it を使用でき、明示的に名前を付ける必要はありません。

fun allCountriesIt() { 
    countries.forEach { println(it.name) } 
}

上記は、次と同等です。

fun allCountriesItExplicit() {
    countries.forEach { it -> println(it.name) }
}

it は、明示的なパラメーターがない場合にのみ、暗黙的なパラメーター名として使用できることに注意してください。

たとえば、次は機能しません。

fun allCountriesExplicit() { 
    countries.forEach { c -> println(it.name) } 
}

また、コンパイル時にエラーが発生します。

Error:(2, 38) Kotlin: Unresolved reference: it

4. ネストされたforEach

すべての国、都市、および通りを反復処理する場合は、ネストされたループを作成できます。

fun allNested() {
    countries.forEach {
        println(it.name)
        it.cities.forEach {
            println(" ${it.name}")
            it.streets.forEach { println("  $it") }
        }
    }
}

ここで、最初の it は国を指し、2番目の it は都市を指し、3番目のitは通りを指します。

ただし、IntelliJを使用すると、次の警告が表示されます。

Implicit parameter 'it' of enclosing lambda is shadowed

これは問題ではないかもしれませんが、6行目では国や都市を参照できなくなりました。 必要に応じて、パラメーターに明示的に名前を付ける必要があります

fun allTable() {
    countries.forEach { c ->
        c.cities.forEach { p ->
            p.streets.forEach { println("${c.name} ${p.name} $it") }
        }
    }
}

5. ネストされたループの代替

ネストされたループは一般に読みにくいため、可能であれば避ける必要があります。 1つのオプションは、 flatMap()を使用することです。

fun allStreetsFlatMap() {
    countries.flatMap { it.cities}
      .flatMap { it.streets}
      .forEach { println(it) }
}

ただし、ネストされた flatMap を使用しない場合、printlnステートメントで都市名または通りの名前にアクセスできません。 上記のメソッドallTable()と同じ出力を取得し、ネストを回避したい場合は、2つの拡張関数を追加できます。

fun City.getStreetsWithCityName() : List<String> {
    return streets.map { "$name, $it" }
      .toList()
}

fun Country.getCitiesWithCountryName() : List<String> {
    return cities.flatMap { it.getStreetsWithCityName() }
      .map { "$name, $it" }
}

次に、これら2つのメソッドを単一のflatMapで使用します。

fun allFlatMapTable() {
    countries.flatMap { it.getCitiesWithCountryName() }
      .forEach { println(it) }
}

6. 結論

この短い記事では、Kotlinでデフォルトパラメーター it を使用する方法と、ネストされたforEachループ内から外部forEachのパラメーターにアクセスする方法を説明しました。 。 最後に、flatMapと拡張関数を使用してネストされたループを回避する方法についても説明しました。

この記事のすべてのコードスニペットは、GitHubリポジトリにあります。