Why does my break statement break “too far”?

落爺英雄遲暮 提交于 2020-01-06 19:58:52

问题


Here's a snippet of my code (based on this previous question):

$rgdNames = (Get-AzureRmResourceGroupDeployment -ResourceGroupName "$azureResGrpName").DeploymentName
$siblings = $rgdNames | Where-Object{$_ -match "^($hostname)(\d+)$" }
if ($siblings) {
    # Make a list of all numbers in the list of hostnames
    $serials = @()
    foreach ($sibling in $siblings) {
        # $sibling -split ($sibling -split '\d+$') < split all digits from end, then strip off everything at the front
        # Then convert it to a number and add that to $serials
        $hostnumber = [convert]::ToInt32([string]$($sibling -split ($sibling -split '\d+$'))[1], 10)
        $serials += $hostnumber
    }
    (1..$siblingsMax) | foreach { # Iterate over all valid serial numbers
        if (!$serials.Contains($_)) { # Stop when we find a serial number that isn't in the list of existing hosts
            $serial = $_
             # break # FIXME: For some reason, this break statement breaks "too far"
        }
    }
} else {
    $serial = 1
}
write-output("serial = $serial") # does not print
# ...more statements here, but they're never called :(

I have been looking at it for a while, but can't figure out why the break statement (if un-commented) stops my program instead of just breaking out of its foreach loop. Is there something about foreach that I'm not aware of, or does break just work differently than it would in Java?

For the time being, I'm working around this using an extra if test, and it doesn't mean (too) much that the loop runs its entire length. But it's ugly!


回答1:


This construct:

(1..$siblingsMax) | foreach { # Iterate over all valid serial numbers
    # do stuff
}

is NOT a foreach loop - it's a pipeline with a call to the ForEach-Object cmdlet (aliased as foreach) - and keywords designed to interrupt the control flow of a loop (like break or continue) will NOT act in the same way in these two different cases.

Use a proper foreach loop and break will behave as you expect:

foreach($i in 1..$siblingsMax){
    # do stuff
    if($shouldBreak)
    {
        break
    }
}

Alternatively, you can abuse the fact that continue behaves like you would expect break in a ForEach-Object process block:

(1..$siblingsMax) | foreach { # Iterate over all valid serial numbers
    if($shouldBreak)
    {
        continue
    }
}

although I would strongly discourage this approach (it'll only lead to more confusion)



来源:https://stackoverflow.com/questions/35172403/why-does-my-break-statement-break-too-far

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!