Почему продолжение ведет себя как разрыв в объекте Foreach? - PullRequest
111 голосов
/ 14 октября 2011

Если я сделаю следующее в скрипте 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 ]

145 голосов
/ 14 октября 2011

Просто используйте 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.

17 голосов
/ 14 октября 2011

Поскольку For-Each объект является командлетом, а не циклом, а продолжение / разрыв не применяются к нему.

Например, если у вас есть:

$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}
3 голосов
/ 14 октября 2011

Другая альтернатива - это своего рода хак, но вы можете заключить свой блок в цикл, который будет выполняться один раз, поэтому продолжение будет иметь желаемый эффект:

1..100 | ForEach-Object {
    for($cont=$true;$cont;$cont=$false){
        if ($_ % 7 -ne 0 ) { continue; }
        Write-Host "$($_) is a multiple of 7"
        }
}
0 голосов
/ 01 июля 2018

Простое выражение 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"}}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...