在for循环中使用break是不好的做法?
在for
循环中使用break
语句是不好的做法?
说,我正在一个数组中寻找一个值。 在for循环中进行比较,当find值时, break;
退出for循环。
这是不好的做法? 我已经看到了使用的替代方法:定义一个variablesvFound
并find值时设置为true,并在for
语句条件检查vFound
。 但是为了这个目的,是否需要创build一个新的variables?
我正在问一个正常的C或C ++循环的上下文。
PS: MISRA编码准则build议不要使用中断。
这里有很多答案,但我还没有看到这个提到:
如果您编写整洁易读的循环,大多数与在for循环中使用break
或continue
相关的“危险”都将被否定。 如果你的循环的主体跨越了几个屏幕的长度,并有多个嵌套的子块,是的,你可以很容易忘记一些代码将不会执行rest后。 但是,如果这个循环是短暂的,那么断言的目的应该是显而易见的。
如果循环变得太大,请在循环中使用一个或多个有名的函数调用。 避免这样做的唯一真正原因是处理瓶颈。
不,rest是正确的解决scheme。
添加布尔variables会使代码更难读取,并增加潜在的错误来源。
你可以find各种各样的专业代码与他们的'打破'的声明。 在必要时使用它是完全有意义的。 在你的情况下,这个选项比创build一个单独的variables更好,只是出于循环的目的。
使用break
以及在for
循环中continue
是非常好的。
它简化了代码并提高了可读性。
Python(和其他语言)远不是坏习惯,扩展了for
循环结构,所以只有在循环没有 break
才会执行它的一部分。
for n in range(5): for m in range(3): if m >= n: print 'stop!' break print m, else: print 'finished.'
输出:
stop! 0 stop! 0 1 stop! 0 1 2 finished. 0 1 2 finished.
等价的代码没有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, if not aborted: print 'finished.'
这取决于语言。 虽然你可以在这里检查一个布尔variables:
for (int i = 0; i < 100 && stayInLoop; i++) { ... }
在数组上运行时不可能这样做:
for element in bigList: ...
无论如何, break
会使两个代码更具可读性。
一般规则:如果遵守规则要求你做一些比较笨拙和难以阅读的事情,那就违反规则,然后打破规则。
在循环的情况下,直到你find了一些东西,你会遇到区分find问题,而不是当你离开时找不到。 那是:
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?
所以没关系,你可以设置一个标志,或者初始化一个“find”值为null。 但
这就是为什么一般来说,我更喜欢把我的search推到function上:
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; }
这也有助于清理代码。 在主线上,“查找”成为一个单一的陈述,当条件复杂时,它们只写一次。
使用break语句没有任何内在的错误,但嵌套循环可能会让人困惑。 为了提高可读性,许多语言( 至lessJava )支持打破标签,这将大大提高可读性。
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; } } }
我会说break(和return)语句经常会增加圈复杂度 ,这使得certificate代码在所有情况下都做正确的事情变得更加困难。
如果您正在考虑在迭代某个特定项目的序列时使用中断,则可能需要重新考虑用于保存数据的数据结构。 使用类似Set或Map的东西可能会提供更好的结果。
打破是一个完全可以接受的语句使用(所以是继续 ,顺便说一句)。 这完全是关于代码可读性的 – 只要你没有太复杂的循环,就没有问题。
这不像他们是一样的联赛。 🙂
在你的例子中,你不知道for循环的迭代次数。 为什么不使用while循环,这使迭代次数在开始时是不确定的?
因此,通常不需要使用break语句 ,因为循环可以更好地表示为while循环。
我同意推荐使用break
其他人。 明显的结果性问题是为什么有人会推荐呢? 那么…当你使用break时,你跳过块中剩下的代码,剩下的迭代。 有时这会导致错误,例如:
-
在块顶部获得的资源可能会在底部被释放(即使对于循环内部的块也是如此),但是当由于断言而导致“过早”退出时,该释放步骤可能被意外跳过(在“现代的“C ++”,“RAII”用于以可靠和exception安全的方式处理这个问题:基本上,对象析构函数可靠地释放资源,而不pipe范围如何退出)
-
有人可能会更改
for
语句中的条件testing,而不会注意到还有其他离开的退出条件 -
ndim的回答指出,有些人可能会避免
break
来维持一个相对一致的循环运行时间,但是你要比较break
和使用布尔型早退出控制variables的情况,
有时候,观察这些错误的人意识到,通过这个“不间断”的规则可以防止/减轻这个错误……实际上,对于“安全的”编程有一个相关的策略,叫做“结构化编程”,每个函数都应该有一个单一的进出口点(即没有转到,不提前回报)。 它可能会消除一些错误,但无疑会引入其他错误。 他们为什么这样做?
- 他们有一个鼓励特定风格的编程/代码的开发框架,而且他们有统计证据表明这在这个有限的框架中产生了净效益,或者
- 他们已经受到这样的框架内的编程指导或经验的影响,或者
- 他们只是独裁的白痴,或者
- 上述任何一种+历史惯性(因为理由比现代C ++更适用于C)。
正如其他人指出的那样,使用break
是完全有效的,它与goto
联赛没有任何关系。
虽然当您想要在循环外部检查在数组中是否find该值时,您可能需要使用vFound
variables。 同样从可维护性的angular度来看,具有通用标志表示退出标准可能是有用的。
我没有看到任何理由,这是一个不好的做法提供,你要完成停止处理在这一点上。
在embedded式世界中,有很多代码使用以下结构:
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;
这是一个非常普遍的例子,幕后发生了很多事情,尤其是中断。 不要使用这个作为样板代码,我只是想说明一个例子。
我个人的观点是,只要采取适当的措施防止无限期地留在循环中,以这种方式编写一个循环就没有问题。
取决于你的用例。 有些应用程序的for循环的运行时间需要保持不变(例如,为了满足一些时序约束,或者将数据内部隐藏到基于时序的攻击)。
在这些情况下,甚至可以设置一个标志,只有在所有for
循环迭代实际运行后才检查标志值。 当然,所有for循环迭代都需要运行相同时间的代码。
如果你不在乎运行时间…使用break;
并continue;
使代码更易于阅读。
关于MISRA 98规则,这是在我的公司在C开发中使用,break语句不应该被使用…
编辑:中断在MISRA '04允许
当然, break;
是停止for循环或foreach循环的解决scheme。 我用它在PHP中的foreach和循环,发现工作。
我不同意!
为什么你会忽略for循环的内置function来创build自己的? 你不需要重新发明轮子。
我认为在你的for循环的顶部有这样的检查是更有意义的
for(int i = 0; i < myCollection.Length && myCollection[i].SomeValue != "Break Condition"; i++) { //loop body }
或者如果您需要先处理该行
for(int i = 0; i < myCollection.Length && (i == 0 ? true : myCollection[i-1].SomeValue != "Break Condition"); i++) { //loop body }
这样你就可以编写一个函数来执行所有的事情,并且制作更清晰的代码。
for(int i = 0; i < myCollection.Length && (i == 0 ? true : myCollection[i-1].SomeValue != "Break Condition"); i++) { DoAllThatCrazyStuff(myCollection[i]); }
或者如果你的情况很复杂,你也可以把这个代码移出来!
for(int i = 0; i < myCollection.Length && BreakFunctionCheck(i, myCollection); i++) { DoAllThatCrazyStuff(myCollection[i]); }
充满rest的“专业代码”对我来说听起来并不像专业代码。 这听起来像是懒惰的编码;)
我对我目前正在使用的代码库(40,000行JavaScript)做了一些分析。
我发现只有22个break
,其中:
- 在
switch
语句中使用了19个(我们总共只有3个switch语句)。 - 2
for
循环内部 – 我立即将其分类为要重构为单独的函数并用return
语句replace的代码。 - 至于循环里面的最后一个
break
…我跑了git blame
看看谁写这个废话!
所以根据我的统计: 如果在switch
外使用break
,这是一种代码异味。
我也search了continue
发言。 没有发现。