哪个是更好的做法 - 对于带有中断或条件循环的循环?

Eri*_*air 26 language-agnostic loops for-loop while-loop

我只是好奇人们对这个话题的看法.假设我有一个对象数组,我想循环遍历它们以查看对象是否包含某些值,如果是,我想停止循环.哪种更好的做法 - 带有中断的for循环或条件循环?

我提供的示例中的伪代码仅用于参数(它也在ActionScript中,因为这是我最近的主要语言).另外,我不是在寻找关于语法的最佳实践想法.

for break循环:

var i:int;

var isBaxterInMilwaukee:Boolean;    

for (i = 0; i < arrayLen; i++)
{
    if (myArray[i]["name"] == "baxter"
         && myArray[i]["location"] == "milwaukee")
    {
        isBaxterInMilwaukee = true;

        barkTwice();

        break;
    }
}
Run Code Online (Sandbox Code Playgroud)

条件循环:

var i:int;

var isBaxterInMilwaukee:Boolean;    

while (!isBaxterInMilwaukee && i < arrayLen)
{
    if (myArray[i]["name"] == "baxter"
         && myArray[i]["location"] == "milwaukee")
    {
        isBaxterInMilwaukee = true;

        barkTwice();
    }

    i++;
}
Run Code Online (Sandbox Code Playgroud)

lc.*_*lc. 31

简而言之,您应该选择最容易阅读和维护的版本.

在较旧的时代,我知道突然出现一个循环被认为是禁忌(与goto声明相同).循环应该在循环条件下破坏而在其他任何地方都没有.因此,while循环将成为可行的方法.

(这可能是程序集的延续,其中循环基本上是一个代码块,在结尾处有一个go-to-the-begin-if-true跳转语句.块中的多个条件跳转语句使得调试非常困难;因此,他们应该避免并在最后合并为一个.)

我觉得这个想法今天似乎有所改变,尤其是对于foreach循环和托管世界; 现在真的是风格问题.当然,除了一些纯粹主义者之外,许多人都可以接受突然发现的循环.请注意,我仍然会避免在while循环中使用break,因为这会混淆循环条件并使其混乱.

如果你允许我使用foreach循环,我认为下面的代码是一个很多更容易比while循环哥阅读:

bool isBaxterInMilwaukee;    

foreach (var item in myArray)
{
    if (item.name == "baxter" && item.location == "milwaukee")
    {
        isBaxterInMilwaukee = true;    
        barkTwice();
        break;
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,随着逻辑的复杂性增加,你可能想要在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;
}
Run Code Online (Sandbox Code Playgroud)

正如Esko Luontola指出的那样,将调用移到barkTwice()此函数之外可能是最好的,因为函数名称中的副作用不明显,也不是在每种情况下都找到Baxter.(或者添加一个布尔参数BarkTwiceIfFound并更改要读取的行if(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();
    }
}
Run Code Online (Sandbox Code Playgroud)

您还可以使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)


And*_*gan 8

我一直不喜欢breaks在代码中的使用...在这种情况下它似乎并不重要,但在更多涉及的循环中,它可能会让另一个读取它的编码器感到困惑.通常,它通常导致不理解循环如何终止,直到编码器发现嵌套break在循环中的深处.通过指定检查循环的每次迭代的标志条件,它使这更清楚.

这个问题类似于return在方法体内深处的语句,它们不容易被发现(而不是设置retVal变量并在方法结束时返回).用一个小方法,这似乎很好,但它越大,它就会越混乱.

它不是一个操作效率的东西,它是一个可维护性的东西.

向你的同事询问特定情况下的可读性和可理解性......这才是真正重要的.


Fer*_*cio 5

我会说这取决于.在这种情况下,带有中断的循环对我来说更清晰.