`pause` et `continuer` dans `forEach` dans Kotlin

Kotlin a de très belles fonctions itératives, comme forEach ou repeat , mais je ne suis pas en mesure de faire les opérateurs break et continue travailler avec eux (à la fois local et non-local):

repeat(5) {
    break
}

(1..5).forEach {
    continue@forEach
}

le but est d'imiter les boucles habituelles avec la syntaxe fonctionnelle aussi proche que possible. C'était certainement possible dans certaines versions plus anciennes de Kotlin, mais j'ai du mal à reproduire la syntaxe.

le problème pourrait être un bug avec labels (M12), mais je pense que le premier exemple devrait fonctionner de toute façon.

il me semble que j'ai lu quelque part à propos d'une astuce/annotation spéciale, mais je n'ai pas pu trouver de référence sur le sujet. Pourrait ressembler à ce qui suit:

public inline fun repeat(times: Int, @loop body: (Int) -> Unit) {
    for (index in 0..times - 1) {
        body(index)
    }
}
35
demandé sur voddan 2015-09-12 19:11:54

4 réponses

Modifier :

Selon le de Kotlin "vieux documents , il devrait être possible d'utiliser des annotations. Cependant, il n'est pas encore mis en œuvre.

Break et continue pour personnalisé les structures de contrôle ne sont pas mis en œuvre pourtant

le issue pour cette fonctionnalité est de 3 ans, donc je suppose qu'il ne va pas être fixé.


Réponse Originale :

Puisque vous fournissez un (Int) -> Unit , vous ne pouvez pas le rompre, puisque le compilateur ne sait pas qu'il est utilisé dans une boucle.

vous avez peu d'options:

utiliser un régulier pour boucle:

for (index in 0..times - 1) {
    // your code here
}

si la boucle est le dernier code de la méthode

vous pouvez utiliser return pour sortir de la méthode (ou return value si elle n'est pas unit la méthode).

utiliser une méthode

Créer une méthode de répétition méthode qui retourne Boolean pour continuer.

public inline fun repeatUntil(times: Int, body: (Int) -> Boolean) {
    for (index in 0..times - 1) {
        if (!body(index)) break
    }
}
16
répondu Yoav Sternberg 2015-09-14 08:22:57

1 à 5. Le return@forEach agit comme le mot-clé continue en Java, ce qui signifie que dans ce cas, il exécute toujours chaque boucle mais passe à la prochaine itération si la valeur est supérieure à 5.

fun main(args: Array<String>) {
    val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    nums.forEach {
       if (it > 5) return@forEach
       println(it)
    }
}

ce sera imprimé 1 à 10 mais saute 5.

fun main(args: Array<String>) {
    val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    nums.forEach {
       if (it == 5) return@forEach
       println(it)
    }
}

de les Essayer à la Kotlin aire de Jeux .

30
répondu s-hunter 2018-01-09 16:43:54

vous pouvez utiliser retour de l'expression lambda qui imite un continue ou break selon votre usage.

C'est couvert dans la question connexe: Comment puis-je faire une "break" ou "continue" quand dans une boucle fonctionnelle à L'intérieur de Kotlin?

20
répondu Jayson Minard 2017-05-23 12:34:39

comme le documentation Kotlin dit , en utilisant return est la voie à suivre. Une bonne chose à propos de kotlin est que si vous avez des fonctions imbriquées, vous pouvez utiliser des étiquettes pour écrire explicitement où votre retour est de:

fun foo() {
  listOf(1, 2, 3, 4, 5).forEach {
    if (it == 3) return // non-local return directly to the caller of foo()
    print(it)
  }
  println("this point is unreachable")
}

et

fun foo() {
  listOf(1, 2, 3, 4, 5).forEach lit@{
    if (it == 3) return@lit // local return to the caller of the lambda, i.e. the forEach loop
    print(it)
  }
  print(" done with explicit label")
}

Vérifiez la documentation, c'est vraiment bon :)

3
répondu cesards 2018-08-22 10:17:28