Зачем продолжать вести себя как перерыв в цикле foreach-объект?
если я делаю следующее В сценарии powershell:
$range = 1..100
ForEach ($_ in $range){
if ($_ % 7 -ne 0 ) { continue; }
Write-Host "$($_) is a multiple of 7"
}
Я получаю ожидаемый результат:
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
однако, если я использую конвейер и ForEach-Object
, продолжить, кажется, вырваться из петли трубопровода.
1..100 | ForEach-Object {
if ($_ % 7 -ne 0 ) { continue; }
Write-Host "$($_) is a multiple of 7"
}
мои вопросы: Могу ли я продолжить подобное поведение, все еще делая ForEach-Object, поэтому мне не нужно разбивать мой конвейер?
4 ответа:
просто использовать
return
вместоcontinue
. Этоreturn
возвращает из блока скрипта, который вызываетсяForEach-Object
на конкретной итерации, таким образом, она имитируетcontinue
в цикле.1..100 | ForEach-Object { if ($_ % 7 -ne 0 ) { return } Write-Host "$($_) is a multiple of 7" }
это нужно иметь в виду при рефакторинге. Иногда кто-то хочет преобразовать
foreach
блок оператора в конвейер сForEach-Object
командлет (он даже имеет псевдонимforeach
что помогает сделать это преобразование легко и ошибиться легко). Всеcontinue
следует заменить наreturn
.P. S. К сожалению, это не так просто сымитировать
break
наForEach-Object
.
, потому что
For-Each
объект-это командлет, а не цикл, и continue / break к нему не применяются.например, если у вас есть:
$b = 1,2,3 foreach($a in $b){ $a | foreach { if($_ -eq 2) {continue;} else {write-host $_} } write-host "after" }
вы получите вывод в виде:
1 after 3 after
это связано с тем, что continue применяется к внешнему циклу foreach, а не к командлету foreach-object. В отсутствие петли, самый внешний уровень, следовательно, давая вам впечатление от него действует как перерыв.
так как же вы получаете продолжение, как поведение? Один из способов-это где-объект, конечно:
1..100 | ?{ $_ % 7 -eq 0} | %{write-host $_ is a mutliple of 7}
другая альтернатива - это своего рода хак, но вы можете обернуть свой блок в цикл, который будет выполняться один раз, таким образом, продолжение будет иметь желаемый эффект:
1..100 | ForEach-Object { for($cont=$true;$cont;$cont=$false){ if ($_ % 7 -ne 0 ) { continue; } Write-Host "$($_) is a multiple of 7" } }
простой оператор else заставляет его работать как есть
1..100 | ForEach-Object { if ($_ % 7 -ne 0 ) { #do nothing } else { Write-Host "$($_) is a multiple of 7" } }
или в одном конвейере
1..100 | ForEach-Object { if ($_ % 7 -ne 0 ) {} else {Write-Host "$($_) is a multiple of 7"}}
но более элегантное решение-инвертировать ваш тест и генерировать результат только для ваших успехов
1..100 | ForEach-Object {if ($_ % 7 -eq 0 ) {Write-Host "$($_) is a multiple of 7"}}