在 break
循环中使用 for
声明是不好的做法吗?
说,我在数组中搜索一个值。比较for循环内部和找到值时,break;
退出for循环。
这是一种不好的做法吗?我已经看到了使用的替代方法:定义变量vFound
并在找到值时将其设置为true,并在vFound
语句条件中检查for
。但是,是否有必要为此目的创建一个新变量?
我在正常的C或C ++ for循环中询问。
P.S:MISRA coding guidelines建议不要使用break。
答案 0 :(得分:130)
不,休息是正确的解决方案。
添加布尔变量会使代码难以阅读并增加潜在的错误来源。
答案 1 :(得分:104)
这里有很多答案,但我还没有看到这个提到:
如果你编写整洁,易读的循环,那么在for循环中使用break
或continue
相关的大多数“危险”都会被否定。如果循环的主体跨越多个屏幕长度并且具有多个嵌套子块,是的,您可能很容易忘记在中断后不会执行某些代码。但是,如果循环很短并且非常重要,那么break语句的目的应该是显而易见的。
如果循环变得太大,请在循环中使用一个或多个命名良好的函数调用。避免这样做的唯一真正原因是处理瓶颈。
答案 2 :(得分:49)
您可以在其中找到各种带有'break'语句的专业代码。在必要时使用它是完全有意义的。在您的情况下,此选项优于仅为了退出循环而创建单独的变量。
答案 3 :(得分:45)
在break
循环中使用continue
和for
完全没问题。
它简化了代码并提高了可读性。
答案 4 :(得分:21)
Python(以及其他语言?)远非不好的做法,扩展了for
loop结构,因此如果循环不仅会被执行> break
。
for n in range(5):
for m in range(3):
if m >= n:
print('stop!')
break
print(m, end=' ')
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, end=' ')
if not aborted:
print('finished.')
答案 5 :(得分:14)
使用break语句没有任何内在错误,但嵌套循环可能会让人感到困惑。为了提高可读性,许多语言(at least Java does)支持打破标签,这将大大提高可读性。
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)语句经常会增加cyclomatic complexity,这使得在所有情况下都很难证明代码正在做正确的事情。
如果您正在考虑在迭代某个特定项目的序列时使用中断,则可能需要重新考虑用于保存数据的数据结构。使用Set或Map之类的东西可以提供更好的结果。
答案 6 :(得分: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?
好的,你可以设置一个标志,或者将“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;
}
这也有助于整理代码。在主线中,“find”成为单个语句,当条件复杂时,它们只写一次。
答案 7 :(得分:13)
这取决于语言。虽然你可以在这里检查一个布尔变量:
for (int i = 0; i < 100 && stayInLoop; i++) { ... }
在数组上进行操作时无法执行此操作:
for element in bigList: ...
无论如何,break
会使两个代码更具可读性。
答案 8 :(得分:13)
中断是一个完全可以接受的声明(继续,顺便说一下)。这都是关于代码可读性的 - 只要你没有过于复杂的循环等等,它就没问题了。
这并不像他们和 goto 一样。 :)
答案 9 :(得分:7)
我同意推荐使用break
的其他人的观点。显而易见的重要问题是为什么有人会这样推荐?好吧......当你使用break时,你跳过块中的其余代码,以及剩余的迭代。有时这会导致错误,例如:
在块顶部获取的资源可以在底部释放(即使对于for
循环内的块也是如此),但是当“过早”时可能会意外跳过该释放步骤exit是由break
语句引起的(在“现代”C ++中,“RAII”用于以可靠和异常安全的方式处理它:基本上,无论退出范围如何,对象析构函数都可以可靠地释放资源)
有人可能会在for
声明中更改条件测试,而不会注意到其他离域退出条件
ndim的回答观察到有些人可能会避免break
来维持一个相对一致的循环运行时,但是你正在比较break
与使用布尔提前退出控制变量的比较
每隔一段时间观察这些错误的人就会意识到可以通过这种“无中断”规则来防止/减轻这种错误......事实上,有一个完整的“安全”编程策略称为“结构化编程”,其中每个函数都是应该也有一个入口和出口点(即没有转到,没有提前返回)。它可能会消除一些错误,但无疑会引入其他错误。他们为什么这样做?
答案 10 :(得分:7)
在您的示例中,您不知道 for 循环的迭代次数。为什么不使用而循环,这允许迭代次数在开始时是不确定的?
因此通常不需要使用 break statemement ,因为循环可以更好地表示为 while 循环。
答案 11 :(得分:5)
使用break
完全有效 - 正如其他人所指出的那样,它与goto
在同一个联盟中无处可去。
虽然您可能希望在循环外检查是否在数组中找到值时使用vFound
变量。同样从可维护性的角度来看,使用公共标志来表示退出标准可能很有用。
答案 12 :(得分:4)
在嵌入式世界中,有很多代码使用以下构造:
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;
这是一个非常通用的例子,幕后发生了很多事情,尤其是中断。不要将它用作样板代码,我只想说明一个例子。
我个人认为,只要采取适当的谨慎措施以防止无限期地留在循环中,以这种方式编写循环没有任何问题。
答案 13 :(得分:4)
我认为没有任何理由说明为什么你想在那时完成STOP处理。
答案 14 :(得分:4)
我对我正在处理的代码库做了一些分析(40,000行JavaScript)。
我发现只有22个break
语句:
switch
语句中使用(我们总共只有3个switch语句!)。for
循环中使用 - 我立即将这些代码重新分类为单独的函数并替换为return
语句。break
内while
循环......我跑git blame
看看谁写了这个垃圾!根据我的统计数据显示:如果在break
之外使用switch
,则会产生代码异味。
我还搜索了continue
个语句。找不到。
答案 15 :(得分:3)
取决于您的使用案例。在某些应用中,for循环的运行时需要保持不变(例如,为了满足某些时序约束,或者将数据内部隐藏在基于时序的攻击中)。
在这些情况下,设置一个标志甚至只检查所有for
循环迭代实际运行后的标志值是有意义的。当然,所有for循环迭代都需要运行仍然需要大约相同时间的代码。
如果您不关心运行时间...请使用break;
和continue;
使代码更易于阅读。
答案 16 :(得分:2)
在我的公司C dev中使用的MISRA 98规则中,不得使用break语句...
编辑:MISRA '04允许休息
答案 17 :(得分:1)
我不同意!
为什么要忽略for循环的内置功能来创建自己的?你不需要重新发明轮子。
我认为将你的支票放在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]);
}
充满休息的“专业代码”对我来说听起来并不像专业代码。这听起来像是懒惰的编码;)
答案 18 :(得分:0)
当然,break;
是停止for循环或foreach循环的解决方案。我在foreach和for循环中使用它在php中找到了工作。