问题
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