160 votes

Pourquoi continue se comporte comme une rupture dans un objet Foreach?

Si je fais ce qui suit dans un script PowerShell:

 $range = 1..100 
ForEach ($_ in $range){
    if ($_ % 7 -ne 0 ) { continue; }
    Write-Host "$($_) is a multiple of 7"
}
 

Je reçois le résultat attendu de:

 7 is a multiple of 7
14 is a multiple of 7
21 is a multiple of 7
28 is a multiple of 7
35 is a multiple of 7
42 is a multiple of 7
49 is a multiple of 7
56 is a multiple of 7
63 is a multiple of 7
70 is a multiple of 7
77 is a multiple of 7
84 is a multiple of 7
91 is a multiple of 7
98 is a multiple of 7
 

Toutefois, si j'utilise un pipeline et que ForEach-Object , continue semble sortir de la boucle de pipeline.

 1..100 | ForEach-Object {
    if ($_ % 7 -ne 0 ) { continue; }
    Write-Host "$($_) is a multiple of 7"
}
 

Ma question est la suivante: est-ce que je peux avoir un comportement semblable à celui que je garde tout en continuant à faire ForEach-Object, afin de ne pas avoir à rompre mon pipeline?

209voto

Roman Kuzmin Points 13913

Utilisez simplement l' return , au lieu de l' continue. Cette return retours à partir du bloc de script qui est appelé par l' ForEach-Object sur une itération particulière, donc, il simule l' continue dans une boucle.

1..100 | ForEach-Object {
    if ($_ % 7 -ne 0 ) { return }
    Write-Host "$($_) is a multiple of 7"
}

C'est un piège à garder à l'esprit sur le refactoring. Parfois, on veut convertir un foreach bloc d'instructions dans un pipeline avec un ForEach-Object applet de commande (il a même l'alias foreach qui permet de faire cette conversion facile de faire des erreurs et facile, trop). Tous continue doit être remplacé par return.

P. S. Malheureusement, il n'est pas facile à simuler break en ForEach-Object.

29voto

manojlds Points 96599

Parce qu' For-Each objet est une applet de commande et pas une boucle et continuer / pause ne s'appliquent pas à elle.

Par exemple, si vous avez:

$b = 1,2,3

foreach($a in $b){

$a | foreach { if($_ -eq 2) {continue;} else {write-host $_} }

write-host "after"

}

vous obtiendrez en sortie:

1
after
3
after

C'est parce que la continuer est appliqué à l'extérieur de la boucle foreach et pas la cmdlet foreach-object. En l'absence d'une boucle externe de niveau, donc en vous donnant l'impression d'agir comme la rupture.

Alors, comment obtenez-vous continuer comme comportement? Une façon est là-objet, bien sûr:

1..100 | ?{ $_ % 7  -eq 0} | %{write-host $_ is a mutliple of 7}

3voto

zdan Points 11822

Une autre alternative est une sorte de bidouille, mais vous pouvez envelopper votre bloc dans une boucle qui s'exécutera une fois, ainsi continuer aura l'effet désiré:

 1..100 | ForEach-Object {
    for($cont=$true;$cont;$cont=$false){
        if ($_ % 7 -ne 0 ) { continue; }
        Write-Host "$($_) is a multiple of 7"
        }
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X