Emboîté pourChaque dans Kotlin

1. Introduction

Dans ce court didacticiel Kotlin, nous examinerons la portée du paramètre dans le lambda d' une boucle forEach .

Tout d'abord, nous définissons les données que nous utiliserons dans nos exemples. Deuxièmement, nous verrons comment utiliser forEach pour parcourir une liste. Troisièmement, nous verrons comment l'utiliser dans des boucles imbriquées.

2. Données de test

Les données que nous utiliserons sont une liste de pays, chacun contenant une liste de villes, qui à son tour, contient une liste de rues:

class Country(val name : String, val cities : List) class City(val name : String, val streets : List) 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. Simple pour chaque

Pour imprimer le nom de chaque pays de la liste, nous pouvons écrire le code suivant:

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

La syntaxe ci-dessus est similaire à Java. Cependant, dans Kotlin, si le lambda accepte un seul paramètre, on peut utiliser ce que le nom du paramètre par défaut et ne pas besoin de le nommer explicitement:

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

Ce qui précède est également équivalent à:

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

Il vaut la peine de noter que nous ne pouvons utiliser ce comme un nom de paramètre implicite s'il n'y a aucun paramètre explicite.

Par exemple, ce qui suit ne fonctionne pas:

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

Et nous verrons une erreur au moment de la compilation:

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

4. Nested forEach

Si nous voulons parcourir tous les pays, villes et rues, nous pouvons écrire une boucle imbriquée:

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

Ici, le premier , il fait référence à un pays, la seconde il à une ville et le troisième il à une rue.

Cependant, si nous utilisons IntelliJ, nous voyons un avertissement:

Implicit parameter 'it' of enclosing lambda is shadowed

Ce n'est peut-être pas un problème, mais à la ligne 6, nous ne pouvons plus faire référence au pays ou à la ville. Si nous voulons cela, nous devons nommer explicitement le paramètre :

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

5. Alternatives aux boucles imbriquées

Les boucles imbriquées sont généralement difficiles à lire et doivent être évitées si possible. Une option consiste à utiliser flatMap () :

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

Cependant, si nous n'utilisons pas de flatMap imbriqué , nous ne pouvons pas accéder au nom de la ville ou de la rue dans l' instruction println . Si nous voulons avoir la même sortie que dans la méthode allTable () ci-dessus et éviter l'imbrication, nous pourrions ajouter deux fonctions d'extension:

fun City.getStreetsWithCityName() : List { return streets.map { "$name, $it" } .toList() } fun Country.getCitiesWithCountryName() : List { return cities.flatMap { it.getStreetsWithCityName() } .map { "$name, $it" } }

Et puis utilisez ces deux méthodes avec un seul flatMap :

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

6. Conclusion

Dans ce court article, nous avons vu comment utiliser le paramètre par défaut it dans Kotlin et comment accéder aux paramètres d'un forEach externe à partir d'une boucle forEach imbriquée . Enfin, nous avons également examiné comment éviter les boucles imbriquées en utilisant flatMap et les fonctions d'extension.

Tous les extraits de code de cet article se trouvent dans notre référentiel GitHub.