在循环内使用break
语句是否不好?for
说,我正在搜索数组中的值。在for循环内进行比较,并在找到值时break;
退出for循环。
这是不好的做法吗?我已经看到了使用替代:定义一个变量vFound
,当被发现的价值它设置为true,并检查vFound
在for
语句条件。但是是否有必要为此目的创建一个新变量?
我问的是在普通的C或C ++ for循环的上下文中。
PS:MISRA编码准则建议不要使用中断。
在循环内使用break
语句是否不好?for
说,我正在搜索数组中的值。在for循环内进行比较,并在找到值时break;
退出for循环。
这是不好的做法吗?我已经看到了使用替代:定义一个变量vFound
,当被发现的价值它设置为true,并检查vFound
在for
语句条件。但是是否有必要为此目的创建一个新变量?
我问的是在普通的C或C ++ for循环的上下文中。
PS:MISRA编码准则建议不要使用中断。
Answers:
这里有很多答案,但是我还没有看到这个问题:
如果编写整洁,易于理解的循环,则与使用break
或continue
在for循环中关联的大多数“危险” 都可以消除。如果循环的主体跨越了几个屏幕长度,并且具有多个嵌套的子块,是的,您很容易忘记在中断之后某些代码将不会执行。但是,如果循环很短并且很关键,则break语句的目的应该显而易见。
如果循环太大,请在循环内使用一个或多个命名良好的函数调用。避免这样做的唯一真实原因是处理瓶颈。
不,休息是正确的解决方案。
添加布尔变量使代码更难阅读,并增加了潜在的错误源。
goto
打出来的水平2+嵌套的循环-因为没有break(level)
在循环中使用break
和都很好。continue
for
它简化了代码并提高了可读性。
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.')
输出:
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.')
使用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;
}
}
}
我要说的是,break(和return)语句通常会增加循环复杂性,这使得在所有情况下都很难证明代码在做正确的事情。
如果在考虑迭代某个特定项目的序列时考虑使用中断,则可能需要重新考虑用于保存数据的数据结构。使用诸如Set或Map之类的东西可能会提供更好的结果。
for
。
break是一个完全可以接受的语句(因此继续)和btw)。这全都与代码的可读性有关—只要您没有过于复杂的循环,就可以了。
好像他们和goto是同一个联赛。:)
一般规则:如果遵循一条规则要求您做一些更尴尬且难以阅读的操作,那么请打破规则,然后再打破规则。
在循环进行直到找到某物的情况下,遇到了将发现时发现与未发现时区分开的问题。那是:
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;
}
这也有助于整理代码。在主行中,“查找”成为单个语句,并且当条件复杂时,它们仅被写入一次。
break
,我会尝试寻找某种方法来将代码重构为函数,以便可以return
代替使用。
在您的示例中,您不知道for循环的迭代次数。为什么不使用while循环来代替,它允许在开始时就不确定迭代次数?
因此,通常不必使用中断状态记忆,因为可以将循环更好地声明为while循环。
我同意建议使用的其他人的观点break
。显而易见的必然问题是,为什么有人会建议呢?好吧...当您使用break时,您将跳过块中的其余代码以及其余的迭代。有时这会导致错误,例如:
在块顶部获取的资源可能在底部释放(即使对于for
循环内的块也是如此),但是当break
语句引起“过早”退出时(在“现代”中),该释放步骤可能会被意外跳过C ++“ RAII”用于以可靠且异常安全的方式处理此问题:基本上,无论如何退出范围,对象析构函数都可靠地释放资源)
有人可能会在for
声明中更改条件测试,而不会注意到还有其他非本地化的退出条件
ndim的答案指出,有些人可能避免break
s来维持相对一致的循环运行时间,但是您正在将其break
与布尔型早退出控制变量的使用进行比较,该变量不成立
人们时不时发现这种错误,就会意识到可以通过“不间断”规则来预防/缓解这些错误……的确,对于“更安全”的编程,有一个整体策略称为“结构化编程”,其中每个功能都应该具有也只有一个入口和出口点(即没有goto,没有提早返回)。它可以消除一些错误,但是无疑会引入其他错误。他们为什么这样做?
break
。的确避免了它,但是没有考虑替代中断的条件。
我对当前正在使用的代码库(40,000行JavaScript)进行了分析。
我发现其中只有22条break
陈述:
switch
语句使用了19个(总共只有3个switch语句!)。for
循环内部使用了2个-我立即将其分类为代码,将其重构为单独的函数并替换为return
语句。break
内部while
循环……我跑去git blame
看看谁写了这个废话!所以根据我的统计:如果break
在之外使用switch
,则是代码异味。
我还搜索continue
语句。一无所获。
我看不出有任何理由说明您要在此时完成STOP处理将是一个不好的做法。
在嵌入式世界中,有很多使用以下构造的代码:
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;
这是一个非常普通的示例,很多事情正在幕后发生,尤其是中断。不要将其用作样板代码,我只是想举例说明。
我个人认为,只要采取适当的措施防止无限期地保留在循环中,以这种方式编写循环就没有错。
continue
应用程序逻辑中没有语句。在那儿?
根据我公司在C dev中使用的MISRA 98规则,不得使用break语句...
编辑:MISRA '04中允许中断
我不同意!
为什么您会忽略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]);
}
在我看来,到处都是断断续续的“专业守则”,听起来并不像是专业守则。听起来像是惰性编码;)
break
人都认为这是为了代码可读性。现在,在疯狂的5英里长的条件再看看上面的循环...
break
在同一个联盟的goto
:)