简而言之,您应该选择最容易阅读和维护的版本。
在稍早的时候,我知道跳出循环被认为是不可取的(与goto语句一样)。循环应该在循环条件上中断,而不是其他地方。因此,使用while循环会是更好的选择。
(这可能是由汇编语言带来的影响,其中循环基本上是一块代码,它在结尾处有一个真跳转语句返回到开头。块中的多个条件跳转语句使得调试变得非常困难;因此应避免在循环体中使用,而将其组合到末尾。)
我觉得这种想法似乎今天已经有所改变了,尤其是在foreach循环和托管世界中;这现在实际上只是一种风格问题。使用break-on-found的for循环现在可能已被许多人接受,当然还有一些纯粹主义者不接受。请注意,我仍然会避免在while循环中使用break,因为这可能会混淆循环条件并使其变得混乱。
如果您允许我使用foreach循环,我认为下面的代码比while循环更容易阅读:
bool isBaxterInMilwaukee;
foreach (var item in myArray)
{
if (item.name == "baxter" && item.location == "milwaukee")
{
isBaxterInMilwaukee = true;
barkTwice();
break;
}
}
然而,随着逻辑复杂度的增加,你可能需要考虑在
break
语句附近添加一个显著的注释,以免它被埋没和难以找到。
可以说,整个代码块都应该重构为自己的函数,不要在找到目标后使用
break
,而是实际上使用
return
返回结果(可以使用 for 循环版本)。
bool isBaxterInMilwaukee(Array myArray)
{
foreach (var item in myArray)
{
if (item.name == "baxter" && item.location == "milwaukee")
{
barkTwice();
return true;
}
}
return false;
}
正如Esko Luontola指出的那样,最好将对barkTwice()的调用移到此函数之外,因为该副作用不明显,与在每种情况下找到Baxter无关。(或者添加一个布尔参数BarkTwiceIfFound并更改该行以读取if(BarkTwiceIfFound) barkTwice();
以使副作用清晰可见。)
顺便说一句,在for循环中也可以进行标志检查而不使用break,但我认为这实际上会影响可读性,因为您不希望在for循环定义中多出一个条件:
var i:int;
var isBaxterInMilwaukee:Boolean;
for (i = 0; !isBaxterInMilwaukee && i < arrayLen; i++)
{
if (myArray[i]["name"] == "baxter"
&& myArray[i]["location"] == "milwaukee")
{
isBaxterInMilwaukee = true;
barkTwice();
}
}
你也可以使用 while 循环模拟自增机制。我不喜欢这种方法,原因有几个:你必须将 i
初始化为真实起始值减一,而且根据编译器如何短路循环条件逻辑,离开循环时 i
的值可能会有所不同。然而,这是可能的,对于某些人来说,这可以提高可读性:
var i:int = -1;
var isBaxterInMilwaukee:Boolean;
while (!isBaxterInMilwaukee && ++i < arrayLen)
{
if (myArray[i]["name"] == "baxter"
&& myArray[i]["location"] == "milwaukee")
{
isBaxterInMilwaukee = true;
barkTwice();
}
}