在for循环中使用break
语句是否是不好的实践?
比如,我正在寻找数组中的一个值。在for循环内部进行比较,当找到该值时,使用break;
退出循环。
这样做是不好的实践吗?我看到了替代方案:定义一个变量vFound
,并在找到值时将其设为true,并在for
语句的条件中检查vFound
。但是为了这个目的而创建一个新变量是必要的吗?
我是在C或C++的普通for循环上下文中提出此问题的。
P.S: MISRA编码指南建议避免使用break语句。
不,break 是正确的解决方案。
添加一个布尔变量会使代码更难以阅读,并增加了潜在的错误来源。
goto
来跳出2级或更多级嵌套循环的原因 - 因为没有break(level)
。 - Петър Петров这里给出了很多答案,但我还没有看到提到以下内容:
在使用for循环中的break
或continue
时,大部分与其相关的“危险”都可以通过编写整洁、易读的循环来消除。如果你的循环体跨越多个屏幕长度并具有多个嵌套子块,那么你很容易忘记在break
之后某些代码将不会被执行。然而,如果循环简短明了,那么break
语句的作用应该是显而易见的。
如果一个循环变得太大,请在循环内部使用一个或多个命名良好的函数调用来代替。唯一真正需要避免这样做的原因是处理瓶颈。
在一些专业的代码中,你可以找到带有“break”语句的各种代码。如果需要,使用它是完全有意义的。在您的情况下,这个选项比为了跳出循环而创建一个单独的变量更好。
在 for
循环中使用 break
和 continue
是完全可以的。
这简化了代码并提高了可读性。
for
循环结构,因此它的一部分仅在循环不 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.')
通用规则:如果遵循一条规则需要你做出更加困难和难以阅读的事情,那么就打破这个规则。
在寻找某些东西的情况下,当你找到它并退出时,你会遇到区分已找到与未找到的问题。也就是说:
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?
所以,你可以设置一个标志,或将“找到”的值初始化为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”变成了一条单独的语句,而当条件比较复杂时,它们只需要编写一次。
break
时,我会尝试将代码重构为一个函数,这样我就可以使用 return
代替它。 - Rene Saarsoo在使用break语句时并没有什么本质的问题,但是嵌套循环会让代码变得混乱。为了提高可读性,许多编程语言(至少Java支持)支持使用标签来进行break,这将极大地改善代码的可读性。
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)语句经常增加圈复杂度,这使得在所有情况下证明代码正确执行变得更加困难。
如果您正在考虑在迭代序列以获取特定项时使用break,则可能需要重新考虑用于保存数据的数据结构。使用类似Set或Map的东西可能会提供更好的结果。
break语句是完全可以使用的(顺便说一下,continue也是)。这取决于代码的可读性——只要您没有过于复杂的循环等,那么使用break语句就没问题。
它不像goto语句一样,它们并不在同一个级别。 :)
这取决于编程语言。虽然在这里您可能可以检查布尔变量:
for (int i = 0; i < 100 && stayInLoop; i++) { ... }
当遍历一个数组时,这是不可能做到的:
for element in bigList: ...
无论如何,break
会使两个代码更易读。break
。显而易见的问题是,为什么会有人推荐不使用呢?原因在于,当你使用break
时,你会跳过块中剩余的代码和迭代。有时这会导致错误,例如:
在块顶部获取的资源可能在底部释放(即使是在for
循环内的块也是如此),但是当break
语句引起“过早”的退出时,释放步骤可能被意外跳过(在“现代”C++中,“RAII”用于以可靠和异常安全的方式处理此问题:基本上,对象析构函数在任何作用域退出时都可以可靠地释放资源)
有人可能更改for
语句中的条件测试,而没有注意到存在其他非局部化的退出条件
ndim的回答指出,有些人可能会避免使用break
来保持相对一致的循环运行时间,但您将break
与使用布尔型的早期退出控制变量进行比较,而这种情况并不成立
偶尔会有人观察到此类错误,意识到可以通过这个“无break”规则来预防/减轻...事实上,还有一种名为“结构化编程”的“更安全”的编程策略,其中每个函数也应该具有单个入口和出口点(即没有goto,没有早期返回)。它可能会消除一些错误,但无疑会引入其他错误。他们为什么要这样做呢?
break
的人在代码中出现错误。他们确实避免了使用 break
,但未能仔细思考替代 break
的条件。 - Tomáš Zato
break
和goto
放在同一级别上 :) - BoltClock