为什么我们应该最小化中断的使用并继续循环?

时间:2022-09-11 10:39:54

When I was a fresh man, my instructor allows us to use break or continue in loops. I do it most of the time back then since it terminates/continue the loop. And now I'm in sophomore years, my instructor told me that the use of break/continue is not advisable. can you tell me why? what affects break/continue by the way?

当我是一个新人时,我的导师允许我们使用休息或继续循环。我大部分时间都在做,因为它终止/继续循环。现在我已经二年级了,我的导师告诉我,使用休息/继续是不可取的。你能告诉我为什么吗?什么影响休息/继续的方式?

3 个解决方案

#1


15  

Some people think that it's bad to have a too complex control flow, which means things like break, continue and multiple returns. The reason is not technical, but mostly that complex control flow can make it harder to verify, test and and reason about a program.

有些人认为控制流过于复杂是很糟糕的,这意味着中断,继续和多次返回。原因不是技术性的,但主要是复杂的控制流程可能使得更难以验证,测试和推理程序。

It is however largely a matter of style, personal taste, and your overall structure. With small, well-purposed functions, there might be little to no harm in having multiple possible flows. In C++ in particular, early exit is a popular idiom and can often make code easier to follow.

然而,这主要取决于风格,个人品味和整体结构。由于功能小,功能齐全,有多种可能的流程可能几乎没有坏处。特别是在C ++中,提前退出是一种流行的习惯用法,通常可以使代码更容易理解。

#2


3  

At least in C, you should not be using break and/or continue "most of the time" (as your question says you used to do) to control the flow of your loops. Your loop condition should indicate under what circumstances the loop should stop; somebody maintaining your code should not have to dig through the code in the body of your loop to see what triggers the break that causes the loop to stop.

至少在C中,您不应该使用break和/或“大部分时间”继续(正如您的问题所说的那样)来控制循环的流程。你的循环条件应该表明循环应该在什么情况下停止;维护你的代码的人不应该深入挖掘循环体中的代码,看看是什么触发了导致循环停止的中断。

For example, let's say you want to read a number of integers from a file inputFile to see if one of the integers is 500. One way of structuring the loop is:

例如,假设您要从文件inputFile中读取一些整数,以查看其中一个整数是否为500.构造循环的一种方法是:

while (fgets (buffer, sizeof (buffer), inputFile)){
    sscanf (buffer, "%d", &num);
    if (num == 500)
       break;
}

Here, the person reading your code has to read your entire while loop to figure out what you are actually looking for in the file. If you write this without the break:

在这里,阅读代码的人必须阅读整个while循环,以找出您在文件中实际查找的内容。如果你在没有休息时写下这个:

while ((num != 500) && fgets (buffer, sizeof (buffer), inputFile)) 
    sscanf (buffer, "%d", &num);

the loop condition itself tells the reader exactly what your code is trying to do, which makes it a lot more easy to understand quickly. Also, as a bonus, you have saved a few lines of code.

循环条件本身告诉读者您的代码正在尝试做什么,这使得它更容易理解。此外,作为奖励,您已经保存了几行代码。

Now imagine a more complicated while or for loop, where the break is buried deep inside the body of the loop. It's easy to see why trying to find the break trigger would get annoying. Having a properly structured loop condition is much more, um, self-documenting.

现在想象一个更复杂的while或for循环,其中break被深埋在循环体内。很容易看出为什么试图找到中断触发器会让人烦恼。具有适当结构化的循环条件更多,嗯,自我记录。

There are, of course, cases where break and continue are in fact good ways to write the code. For example, if the condition at which the loop should end might occur in the middle of the loop execution, and there's a long set of statements that follow inside the loop, and executing those statements would add processing time without accomplishing anything useful, sure, go ahead and use the break. But those cases are the exception, not the "most of the time".

当然,有些情况下,break和continue实际上是编写代码的好方法。例如,如果循环应该结束的条件可能在循环执行的中间发生,并且循环内部有一长串语句,并且执行这些语句会增加处理时间而不会完成任何有用的操作,当然,继续使用休息。但这些案例是例外,而不是“大部分时间”。

#3


2  

Most of the logic I've seen for reasoning about code correctness supposes single entry/single exit. If your loops are filled with break and continue, it becomes impossible to know whether your loop invariants are met, or whether you always make progress (so the loop won't be endless). (Note that the do { ... } while (...); loop also suffers from this; the loop invariants aren't established the first time through, which can lead to some surprises.)

我在推理代码正确性时看到的大部分逻辑都假设单入口/单出口。如果你的循环充满了break并继续,则无法知道你的循环不变量是否得到满足,或者你是否总是取得进展(所以循环不会无穷无尽)。 (注意do {...} while(...);循环也会受此影响;第一次没有建立循环不变量,这可能会导致一些意外。)

Most of the cases where you are tempted to use break or continue, you've probably made the loop (and the function which contains it) too large and too complex.

在大多数情况下,你很想使用break或continue,你可能已经使循环(以及包含它的函数)太大而且太复杂。

Some would argue that something like:

有人会争辩说:

for (;;) {
    //  ...
    if ( conditionMet ) {
        break;
    }
    //  ...
}

would be acceptable for the classical loop and a half idiom; it is single entry/single exit, after all, even if the exit isn't quite where we expect it (and is very hard to find when reading the code). The problem concerning loop invariants remains; the aren't met before the if, at least the first time through. Generally, a better solution would be to put the code before the test into a separate function, which returns conditionMet, and use:

对于经典的循环和半成语是可以接受的;毕竟,它是单入口/单出口,即使出口不在我们预期的位置(并且在阅读代码时很难找到)。关于循环不变量的问题仍然存在;在if之前没有达到,至少第一次通过。通常,更好的解决方案是将测试前的代码放入一个单独的函数中,该函数返回conditionMet,并使用:

while ( doLoopPrefix() ) {
    doLoopSuffix();
}

(In general, if your loop is more than three or four lines, you should refactor. Except maybe if it contains a single switch statement, with a lot of cases.)

(一般来说,如果你的循环超过三行或四行,你应该重构。除非它包含一个switch语句,但很多情况下。)

#1


15  

Some people think that it's bad to have a too complex control flow, which means things like break, continue and multiple returns. The reason is not technical, but mostly that complex control flow can make it harder to verify, test and and reason about a program.

有些人认为控制流过于复杂是很糟糕的,这意味着中断,继续和多次返回。原因不是技术性的,但主要是复杂的控制流程可能使得更难以验证,测试和推理程序。

It is however largely a matter of style, personal taste, and your overall structure. With small, well-purposed functions, there might be little to no harm in having multiple possible flows. In C++ in particular, early exit is a popular idiom and can often make code easier to follow.

然而,这主要取决于风格,个人品味和整体结构。由于功能小,功能齐全,有多种可能的流程可能几乎没有坏处。特别是在C ++中,提前退出是一种流行的习惯用法,通常可以使代码更容易理解。

#2


3  

At least in C, you should not be using break and/or continue "most of the time" (as your question says you used to do) to control the flow of your loops. Your loop condition should indicate under what circumstances the loop should stop; somebody maintaining your code should not have to dig through the code in the body of your loop to see what triggers the break that causes the loop to stop.

至少在C中,您不应该使用break和/或“大部分时间”继续(正如您的问题所说的那样)来控制循环的流程。你的循环条件应该表明循环应该在什么情况下停止;维护你的代码的人不应该深入挖掘循环体中的代码,看看是什么触发了导致循环停止的中断。

For example, let's say you want to read a number of integers from a file inputFile to see if one of the integers is 500. One way of structuring the loop is:

例如,假设您要从文件inputFile中读取一些整数,以查看其中一个整数是否为500.构造循环的一种方法是:

while (fgets (buffer, sizeof (buffer), inputFile)){
    sscanf (buffer, "%d", &num);
    if (num == 500)
       break;
}

Here, the person reading your code has to read your entire while loop to figure out what you are actually looking for in the file. If you write this without the break:

在这里,阅读代码的人必须阅读整个while循环,以找出您在文件中实际查找的内容。如果你在没有休息时写下这个:

while ((num != 500) && fgets (buffer, sizeof (buffer), inputFile)) 
    sscanf (buffer, "%d", &num);

the loop condition itself tells the reader exactly what your code is trying to do, which makes it a lot more easy to understand quickly. Also, as a bonus, you have saved a few lines of code.

循环条件本身告诉读者您的代码正在尝试做什么,这使得它更容易理解。此外,作为奖励,您已经保存了几行代码。

Now imagine a more complicated while or for loop, where the break is buried deep inside the body of the loop. It's easy to see why trying to find the break trigger would get annoying. Having a properly structured loop condition is much more, um, self-documenting.

现在想象一个更复杂的while或for循环,其中break被深埋在循环体内。很容易看出为什么试图找到中断触发器会让人烦恼。具有适当结构化的循环条件更多,嗯,自我记录。

There are, of course, cases where break and continue are in fact good ways to write the code. For example, if the condition at which the loop should end might occur in the middle of the loop execution, and there's a long set of statements that follow inside the loop, and executing those statements would add processing time without accomplishing anything useful, sure, go ahead and use the break. But those cases are the exception, not the "most of the time".

当然,有些情况下,break和continue实际上是编写代码的好方法。例如,如果循环应该结束的条件可能在循环执行的中间发生,并且循环内部有一长串语句,并且执行这些语句会增加处理时间而不会完成任何有用的操作,当然,继续使用休息。但这些案例是例外,而不是“大部分时间”。

#3


2  

Most of the logic I've seen for reasoning about code correctness supposes single entry/single exit. If your loops are filled with break and continue, it becomes impossible to know whether your loop invariants are met, or whether you always make progress (so the loop won't be endless). (Note that the do { ... } while (...); loop also suffers from this; the loop invariants aren't established the first time through, which can lead to some surprises.)

我在推理代码正确性时看到的大部分逻辑都假设单入口/单出口。如果你的循环充满了break并继续,则无法知道你的循环不变量是否得到满足,或者你是否总是取得进展(所以循环不会无穷无尽)。 (注意do {...} while(...);循环也会受此影响;第一次没有建立循环不变量,这可能会导致一些意外。)

Most of the cases where you are tempted to use break or continue, you've probably made the loop (and the function which contains it) too large and too complex.

在大多数情况下,你很想使用break或continue,你可能已经使循环(以及包含它的函数)太大而且太复杂。

Some would argue that something like:

有人会争辩说:

for (;;) {
    //  ...
    if ( conditionMet ) {
        break;
    }
    //  ...
}

would be acceptable for the classical loop and a half idiom; it is single entry/single exit, after all, even if the exit isn't quite where we expect it (and is very hard to find when reading the code). The problem concerning loop invariants remains; the aren't met before the if, at least the first time through. Generally, a better solution would be to put the code before the test into a separate function, which returns conditionMet, and use:

对于经典的循环和半成语是可以接受的;毕竟,它是单入口/单出口,即使出口不在我们预期的位置(并且在阅读代码时很难找到)。关于循环不变量的问题仍然存在;在if之前没有达到,至少第一次通过。通常,更好的解决方案是将测试前的代码放入一个单独的函数中,该函数返回conditionMet,并使用:

while ( doLoopPrefix() ) {
    doLoopSuffix();
}

(In general, if your loop is more than three or four lines, you should refactor. Except maybe if it contains a single switch statement, with a lot of cases.)

(一般来说,如果你的循环超过三行或四行,你应该重构。除非它包含一个switch语句,但很多情况下。)