Зачем продолжать вести себя как перерыв в цикле 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"}}