为什么“继续”?表现得像“打破”在 Foreach 对象中?

发布于 2024-12-09 11:41:11 字数 826 浏览 1 评论 0原文

如果我在 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-Objectcontinue 似乎会突破管道循环。

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

我可以在执行 ForEach-Object 的同时获得类似 continue 的行为,这样我就不必破坏我的管道吗?

If I do the following in a PowerShell script:

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

I get the expected output of:

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

However, if I use a pipeline and ForEach-Object, continue seems to break out of the pipeline loop.

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

Can I get a continue-like behavior while still doing ForEach-Object, so I don't have to breakup my pipeline?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

满栀 2024-12-16 11:41:11

只需使用返回而不是继续即可。此 return 从特定迭代中由 ForEach-Object 调用的脚本块返回,因此,它模拟循环中的 continue

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

重构时需要记住一个问题。有时,人们想要使用 ForEach-Object cmdlet 将 foreach 语句块转换为管道(它甚至具有别名 foreach ,有助于使这种转换很容易,也很容易出错)。所有继续都应替换为返回

PS:不幸的是,在ForEach-Object中模拟break并不是那么容易。

Simply use the return instead of the continue. This return returns from the script block which is invoked by ForEach-Object on a particular iteration, thus, it simulates the continue in a loop.

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

There is a gotcha to be kept in mind when refactoring. Sometimes one wants to convert a foreach statement block into a pipeline with a ForEach-Object cmdlet (it even has the alias foreach that helps to make this conversion easy and make mistakes easy, too). All continues should be replaced with return.

P.S.: Unfortunately, it is not that easy to simulate break in ForEach-Object.

花开雨落又逢春i 2024-12-16 11:41:11

因为 For-Each 对象是一个 cmdlet,而不是循环,并且 continuebreak 不适用于它。

例如,如果您有:

$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 cmdlet。如果没有循环,则为最外层,因此给您的印象是它的行为类似于 break

那么如何获得类似继续的行为呢?一种方法当然是 Where-Object

1..100 | ?{ $_ % 7  -eq 0} | %{Write-Host $_ is a multiple of 7}

Because For-Each object is a cmdlet and not a loop and continue and break do not apply to it.

For example, if you have:

$b = 1,2,3

foreach($a in $b) {

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

    Write-Host  "after"
}

You will get output as:

1
after
3
after

It is because the continue gets applied to the outer foreach loop and not the foreach-object cmdlet. In absence of a loop, the outermost level, hence giving you an impression of it acting like break.

So how do you get a continue-like behaviour? One way is Where-Object of course:

1..100 | ?{ $_ % 7  -eq 0} | %{Write-Host $_ is a multiple of 7}
短叹 2024-12-16 11:41:11

一个简单的 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"}}

A simple else statement makes it work as in:

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

Or in a single pipeline:

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

But a more elegant solution is to invert your test and generate output for only your successes

1..100 | ForEach-Object {if ($_ % 7 -eq 0 ) {Write-Host "$($_) is a multiple of 7"}}
往事随风而去 2024-12-16 11:41:11

另一种选择是一种 hack,但您可以将块包装在一个将执行一次的循环中。这样,继续就会达到预期的效果:

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

Another alternative is kind of a hack, but you can wrap your block in a loop that will execute once. That way, continue will have the desired effect:

1..100 | ForEach-Object {
    for ($cont=$true; $cont; $cont=$false) {
        if ($_ % 7 -ne 0 ) { continue; }
        Write-Host "$($_) is a multiple of 7"
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文