在for循环中使用break是不好的做法吗?

kik*_*iki 118 for-loop break

在循环中使用break语句是不好的做法?for

说,我在数组中搜索一个值.比较for循环内部和找到值时,break;退出for循环.

这是一种不好的做法吗?我已经看到了使用替代:定义一个变量vFound,当被发现的价值它设置为true,并检查vFound在for语句条件.但是,是否有必要为此目的创建一个新变量?

我在正常的C或C++ for循环的上下文中询问.

PS:MISRA编码指南建议不要使用break.

smi*_*man 132

不,休息是正确的解决方案.

添加布尔变量会使代码更难读取并添加潜在的错误源.

  • 我宁愿把循环代码放在一个函数中,然后返回.这避免了goto,并将您的代码分成更小的块. (3认同)
  • 同意.特别是如果您希望在多个条件下退出循环.留下循环的布尔值可能会让人感到困惑. (2认同)
  • 这就是为什么我使用 `goto` 来跳出 Level 2+ 嵌套循环 - 因为没有 `break(level)` (2认同)

e.J*_*mes 112

这里有很多答案,但我还没有看到这个提到:

如果你编写整洁,易读的循环,那么与使用break或continuefor循环相关的大多数"危险"都会被否定.如果循环的主体跨越多个屏幕长度并且具有多个嵌套子块,是的,您可能很容易忘记在中断后不会执行某些代码.但是,如果循环很短且非常重要,则break语句的目的应该是显而易见的.

如果循环变得太大,请在循环中使用一个或多个命名良好的函数调用.避免这样做的唯一真正原因是处理瓶颈.

  • 很正确.当然,如果循环是如此庞大和复杂,以至于很难看出其中发生了什么,那么无论你是否有休息,这都是一个问题. (8认同)
  • 另一个问题是,break 和 continue 会导致重构出现问题。这可能表明这是一种不好的做法。使用 if 语句时代码的意图也更加清晰。 (2认同)

Ami*_*t S 50

您可以在其中找到各种带有"break"语句的专业代码.在必要时使用它是完全有意义的.在您的情况下,此选项优于仅为了退出循环而创建单独的变量.


小智 45

使用break以及continue在for循环是完全没有问题.

它简化了代码并提高了可读性.


Nic*_*k T 21

Python(以及其他语言?)远非不好的做法,它扩展了for循环结构,因此只有循环不 执行才能执行部分循环结构break.

for n in range(5):
    for m in range(3):
        if m >= n:
            print('stop!')
            break
        print(m, end=' ')
    else:
        print('finished.')
Run Code Online (Sandbox Code Playgroud)

输出:

stop!
0 stop!
0 1 stop!
0 1 2 finished.
0 1 2 finished.
Run Code Online (Sandbox Code Playgroud)

没有break和那个方便的等效代码else:

for n in range(5):
    aborted = False
    for m in range(3):
        if not aborted:
            if m >= n:
                print('stop!')
                aborted = True
            else:            
                print(m, end=' ')
    if not aborted:
        print('finished.')
Run Code Online (Sandbox Code Playgroud)

  • 哦,我喜欢这样,有时也希望在 C 中使用它。语法也很好,可以毫无歧义地适应未来的类 C 语言。 (2认同)

Jay*_*Jay 14

一般规则:如果遵循规则要求您做一些更尴尬和难以阅读的事情然后违反规则,那么打破规则.

在循环直到你找到某些东西的情况下,你会遇到区分发现与未找到的问题.那是:

for (int x=0;x<fooCount;++x)
{
  Foo foo=getFooSomehow(x);
  if (foo.bar==42)
    break;
}
// So when we get here, did we find one, or did we fall out the bottom?
Run Code Online (Sandbox Code Playgroud)

好的,你可以设置一个标志,或者将"found"值初始化为null.但

这就是为什么我更喜欢将我的搜索推送到函数中:

Foo findFoo(int wantBar)
{
  for (int x=0;x<fooCount;++x)
  {
    Foo foo=getFooSomehow(x);
    if (foo.bar==wantBar)
      return foo;
  }
  // Not found
  return null;
}
Run Code Online (Sandbox Code Playgroud)

这也有助于整理代码.在主线中,"find"成为单个语句,当条件复杂时,它们只写一次.

  • 正是我想说的。通常,当我发现自己在使用 `break` 时,我会尝试找到某种方法将代码重构为一个函数,这样我就可以使用 `return` 来代替。 (2认同)

cyb*_*onk 14

使用break语句没有任何内在错误,但嵌套循环可能会让人感到困惑.为了提高可读性,许多语言(至少Java确实如此)支持打破标签,这将极大地提高可读性.

int[] iArray = new int[]{0,1,2,3,4,5,6,7,8,9};
int[] jArray = new int[]{0,1,2,3,4,5,6,7,8,9};

// label for i loop
iLoop: for (int i = 0; i < iArray.length; i++) {

    // label for j loop
    jLoop: for (int j = 0; j < jArray.length; j++) {

        if(iArray[i] < jArray[j]){
            // break i and j loops
            break iLoop;
        } else if (iArray[i] > jArray[j]){  
            // breaks only j loop
            break jLoop;
        } else {
            // unclear which loop is ending
            // (breaks only the j loop)
            break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我会说断开(和返回)语句通常会增加圈复杂度,这使得在所有情况下证明代码执行正确的事情变得更加困难.

如果您正在考虑在迭代某个特定项目的序列时使用中断,则可能需要重新考虑用于保存数据的数据结构.使用Set或Map之类的东西可以提供更好的结果.

  • 圈复杂度为+1. (3认同)

eum*_*iro 13

这取决于语言.虽然你可以在这里检查一个布尔变量:

for (int i = 0; i < 100 && stayInLoop; i++) { ... }
Run Code Online (Sandbox Code Playgroud)

在数组上进行itering时无法执行此操作:

for element in bigList: ...
Run Code Online (Sandbox Code Playgroud)

无论如何,break会使两个代码更具可读性.


riv*_*era 13

break是一个完全可以接受的语句(所以继续,顺便说一句).这都是关于代码可读性的 - 只要你没有过于复杂的循环等等,它就没问题了.

这并不像他们和goto一样.:)

  • goto的问题在于你可以将它指向任何地方.中断和继续都保留了代码的模块性.该参数与每个函数具有单个出口点的级别相同. (3认同)
  • @glenatron goto的问题不是goto语句,而是goto跳转到的标签的引入就是问题.当你读到goto语句时,控制流程没有不确定性.当您阅读标签时,控制流程存在很多不确定性(将控制转移到此标签的所有部分都在哪里?).break语句不会引入标签,因此不会引入任何新的复杂情况. (2认同)

Sch*_*ler 7

在您的示例中,您不知道for循环的迭代次数.为什么不使用while循环,这允许迭代次数在开始时是不确定的?

因此,通常不必使用中断状态,因为循环可以更好地表示为while循环.

  • 在给出的示例中 - 在数组中搜索键,for循环是正确的惯用构造.您不使用while循环遍历数组.你使用for循环.(或者每个循环,如果可用的话).你这样做是出于对其他程序员的礼貌,因为他们认为"for(int i = 0; i <ra.length; i ++){}"立即构造为"遍历数组"为此构造添加一个中断只是一个"如果可以的话尽早退出"声明. (2认同)

Ton*_*roy 7

我同意推荐使用的其他人break.显而易见的重要问题是为什么有人会这样推荐?好吧......当你使用break时,你跳过块中的其余代码,以及剩余的迭代.有时这会导致错误,例如:

  • 在块顶部获取的资源可以在底部释放(即使对于for循环内的块也是如此),但是当break语句(在"现代"中)导致"过早"退出时,可能会意外跳过该释放步骤C++,"RAII"用于以可靠和异常安全的方式处理这个问题:基本上,无论退出范围如何,对象析构函数都可以可靠地释放资源)

  • 有人可能会在for声明中更改条件测试而不会注意到其他非本地化的退出条件

  • ndim的回答观察到有些人可能会避免使用breaks来保持相对一致的循环运行时间,但是你要比较break使用布尔值早期退出控制变量而不是

观察这些错误的人偶尔会意识到可以通过这种"无中断"规则来防止/减轻这种错误......事实上,有一个完整的"安全"编程策略称为"结构化编程",其中每个函数应该具有单个入口和出口点(即没有转到,没有提前返回).它可能会消除一些错误,但无疑会引入其他错误.他们为什么这样做?

  • 他们有一个鼓励特定风格的编程/代码的开发框架,他们有统计证据证明这在有限的框架中产生了净收益,或者
  • 他们受到编程指南或这种框架中的经验的影响,或者
  • 他们只是独裁的白痴,或者
  • 任何上述+历史惯性(相关的理由更适用于C而不是现代C++).


小智 5

使用完全有效break- 正如其他人所指出的那样,它在同一个联盟中无处可去goto.

虽然您可能希望vFound在循环外部检查是否在数组中找到该值时使用该变量.同样从可维护性的观点来看,具有用信号通知退出标准的公共标志可能是有用的.


Nat*_*ate 5

在嵌入式世界中,有很多代码使用以下结构:

    while(1)
    { 
         if (RCIF)
           gx();
         if (command_received == command_we_are_waiting_on)
           break;
         else if ((num_attempts > MAX_ATTEMPTS) || (TickGet() - BaseTick > MAX_TIMEOUT))
           return ERROR;
         num_attempts++;
    }
    if (call_some_bool_returning_function())
      return TRUE;
    else
      return FALSE;
Run Code Online (Sandbox Code Playgroud)

这是一个非常普遍的例子,很多事情都在幕后发生,特别是中断。不要将此用作样板代码,我只是想说明一个示例。

我个人的观点是,只要采取适当的措施防止无限期地保留在循环中,以这种方式编写循环并没有什么问题。


小智 5

如果您想在此时完成 STOP 处理,我不认为这是一个不好的做法。


Ren*_*soo 5

我对当前正在使用的代码库(40,000行JavaScript)进行了一些分析。

我发现其中只有22条break陈述:

  • 内部switch语句使用了19个(总共只有3个switch语句!)。
  • 在for循环内部使用了2个-我立即将其分类为代码,将其重构为单独的函数并替换为return语句。
  • 至于最后的break内部while循环……我跑去git blame看看谁写了这个废话!

所以根据我的统计:如果break在之外使用switch,则是代码异味。

我还搜索continue语句。一无所获。