Est-il possible de break
partir d'un Groovy .each{Closure}
ou devrais-je utiliser une boucle classique à la place?
Est-il possible de break
partir d'un Groovy .each{Closure}
ou devrais-je utiliser une boucle classique à la place?
Réponses:
Non, vous ne pouvez pas abandonner un «chacun» sans lancer une exception. Vous souhaiterez probablement une boucle classique si vous souhaitez que l'interruption s'interrompe dans une condition particulière.
Alternativement, vous pouvez utiliser une fermeture «find» au lieu d'un each et retourner true lorsque vous auriez fait une pause.
Cet exemple s'arrêtera avant de traiter toute la liste:
def a = [1, 2, 3, 4, 5, 6, 7]
a.find {
if (it > 5) return true // break
println it // do the stuff that you wanted to before break
return false // keep looping
}
Tirages
1
2
3
4
5
mais n'imprime pas 6 ou 7.
Il est également très facile d'écrire vos propres méthodes d'itération avec un comportement de rupture personnalisé qui accepte les fermetures:
List.metaClass.eachUntilGreaterThanFive = { closure ->
for ( value in delegate ) {
if ( value > 5 ) break
closure(value)
}
}
def a = [1, 2, 3, 4, 5, 6, 7]
a.eachUntilGreaterThanFive {
println it
}
Imprime également:
1
2
3
4
5
find
mieux que any
- voir l'autre réponse ci-dessous de @Michal que l'on travaille pour moi
def test = [2] test.findResult{ it * 2 }
retournera 4 au lieu de 2
Remplacez chaque boucle par n'importe quelle fermeture.
def list = [1, 2, 3, 4, 5]
list.any { element ->
if (element == 2)
return // continue
println element
if (element == 3)
return true // break
}
Production
1
3
any()
de cette manière est un peu trompeur, mais cela fonctionne certainement et vous donne la possibilité de rompre ou de continuer .
Non, vous ne pouvez pas rompre avec une fermeture dans Groovy sans lancer une exception. De plus, vous ne devez pas utiliser d'exceptions pour le flux de contrôle.
Si vous avez envie de sortir d'une clôture, vous devriez probablement d'abord vous demander pourquoi vous voulez faire cela et non comment le faire. La première chose à considérer pourrait être la substitution de la fermeture en question par l'une des fonctions d'ordre supérieur (conceptuel) de Groovy. L'exemple suivant:
for ( i in 1..10) { if (i < 5) println i; else return}
devient
(1..10).each{if (it < 5) println it}
devient
(1..10).findAll{it < 5}.each{println it}
ce qui contribue également à la clarté. Il énonce bien mieux l'intention de votre code.
L'inconvénient potentiel des exemples illustrés est que l'itération ne s'arrête que tôt dans le premier exemple. Si vous avez des considérations de performances, vous voudrez peut-être l'arrêter immédiatement.
Cependant, pour la plupart des cas d'utilisation qui impliquent des itérations, vous pouvez généralement recourir à l'une des méthodes find, grep, collect, inject, etc. de Groovy. Ils prennent généralement une certaine "configuration" et ensuite "savent" comment faire l'itération pour vous, de sorte que vous puissiez réellement éviter les boucles impératives dans la mesure du possible.
Juste en utilisant une fermeture spéciale
// declare and implement:
def eachWithBreak = { list, Closure c ->
boolean bBreak = false
list.each() { it ->
if (bBreak) return
bBreak = c(it)
}
}
def list = [1,2,3,4,5,6]
eachWithBreak list, { it ->
if (it > 3) return true // break 'eachWithBreak'
println it
return false // next it
}
(1..10) .chaque {
si (il <5)
imprimer
autre
retourner faux
each
, il n'imprime tout simplement pas les valeurs supérieures à 4. C'est else
superflu, votre code ferait de même sans lui. En outre, vous pouvez prouver each
que vous ne rompez pas avec return false
si vous mettez println "not breaking"
juste après else
et juste avant return false
.
Vous pourriez passer RETURN
. Par exemple
def a = [1, 2, 3, 4, 5, 6, 7]
def ret = 0
a.each {def n ->
if (n > 5) {
ret = n
return ret
}
}
Ça marche pour moi!
any
méthode du tableau en retournantfalse
. Vous ne pouvez pas interrompre la each
méthode de la même manière.