简而言之,您应该选择最容易阅读和维护的版本。
在稍早的时候,我知道打破循环被认为是一个禁忌(与 goto 语句相提并论)。循环应该在循环条件下中断,而不是在其他任何地方。因此,while 循环将是要走的路。
(这可能是汇编的保留,其中循环基本上是一个代码块,最后有一个 go-to-the-beginning-if-true 跳转语句。块中的多个条件跳转语句使其非常难以调试; 因此,它们将被避免并在最后合二为一。)
我觉得这个想法今天似乎发生了一些变化,尤其是对于 foreach 循环和托管世界;现在真的是风格问题。Break-on-found for 循环可能已经为许多人所接受,当然除了一些纯粹主义者。请注意,我仍然会避免在 while 循环中使用 break,因为这会混淆循环条件并使其混乱。
如果您允许我使用 foreach 循环,我认为下面的代码比它的 while-loop 兄弟更容易阅读:
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
并将行更改为 readif(BarkTwiceIfFound) barkTwice();
以使副作用清晰。)
作为记录,您也可以在 for 循环中不中断地进行标志检查,但我觉得这实际上会损害可读性,因为您不希望在 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();
}
}