我的老板总是不屑一顾地提到糟糕的程序员在循环中使用breakcontinue

我一直都在使用它们,因为它们很有意义。让我向您展示灵感:



 function verify(object) {
    if (object->value < 0) return false;
    if (object->value > object->max_value) return false;
    if (object->name == "") return false;
    ...
}
 


这里的要点是,首先该功能检查条件是否正确,然后执行实际功能。 IMO同样适用于循环:

 while (primary_condition) {
    if (loop_count > 1000) break;
    if (time_exect > 3600) break;
    if (this->data == "undefined") continue;
    if (this->skip == true) continue;
    ...
}
 


我认为这使阅读和调试更加容易;但我也没有看到不利之处。

评论

无需花费太多时间就忘记哪个人在做什么。

不。goto都不是。知道何时使用它们是关键。它们是工具箱中的工具。当它们提供清晰简洁的代码时,您可以使用它们。

我对这种编码风格的支持不够强烈。嵌套条件的多个级别比这种方法差得多。我通常不喜欢编码风格,但这对我来说几乎是一个大难题。

显然,您的老板没有编写(足够)的代码。如果他这样做了,他会知道所有关键字(是,甚至goto)在某些情况下都是有用的。

糟糕的程序员使用break and continue并不意味着好的程序员不会。糟糕的程序员也会同时使用if和while。

#1 楼

在块的开头使用时,首先进行检查,它们就像前提条件一样,所以很好。

在块的中间使用,周围有一些代码,它们的作用就像隐藏的陷阱,所以不好。

评论


@Klaim:可以争论的是,具有多个退出点的任何例程都是糟糕的例程。一个适当分解的例程应该只做一件事和一件事。

–位旋转器
2011-3-16在13:45

@ bit-twiddler:这是非常C语言的心态。以后可以修改一个临时变量,因此从此处向下20行打错一个错字可能会删除精心制作的结果。但是,立即返回(或中断或继续)非常清楚:我现在可以停止阅读,因为我知道它不可能进一步修改。这对我的小脑袋有好处,确实使遍历代码更容易。

– Matthieu M.
2011年3月17日19:00

@Matthieu我同意。当您收到满足该块目的的结果时,退出该块。

–伊文·普莱斯
2011-3-19在5:48

@ bit-twiddler-单出口原则与单责任原则是分开的。我不同意检查总是与单独执行WRT分开。实际上,“单一责任”始终是一个主观名词。例如,在二次求解器中,计算判别式是否应单独负责?还是整个二次公式可以是一个责任?我认为这取决于您是否将判别式单独使用-否则,将其视为独立的责任可能过度。

–Steve314
2011年10月6日上午8:35

答案是经验法则,不是硬性规定。它在大多数情况下都有效,如果在您的上下文中有意义的话,请随时进行破坏。

–克莱姆
14年7月29日在23:13

#2 楼

您可以阅读Donald Knuth在1974年发表的论文《结构化编程》中的“转到语句”,其中他讨论了go to在结构上理想的各种用法。它们包括breakcontinue语句的等效项(其中go to的许多用法已开发成更为有限的构造)。

(这些示例引起了我的兴趣。通常,喜欢任何代码的一个入口和一个出口的人都不喜欢breakcontinue,并且这种人也对多个return语句不满意。)

评论


大多数喜欢功能和过程具有单个入口和出口点的人都是在Pascal上长大的。 Pascal并不是我学到的第一门语言,但是它对当今的代码结构产生了深远的影响。人们总是评论读取我的Java代码有多么容易。那是因为我避免了多个出口点以及将声明与代码混合在一起。我尽力在方法顶部声明在方法中使用的每个局部变量。这种做法通过迫使我保持​​方法简洁来避免代码混乱。

–位旋转器
2011年3月15日15:37



Pascal还具有嵌套功能。只是在说'...

–Shog9
2011-3-15在17:32

据我所记得,在过去,人们不喜欢函数中的多个return语句的主要原因是因为调试器无法正确处理它们。在函数的末尾设置一个断点确实很痛苦,但是由于使用了更早的return语句,您从未遇到过断点。对于如今我使用的每个编译器,这不再是问题。

–扣篮
2011-3-15在19:16

@ bit-twiddler:我不太确定。我今天仍在使用Pascal,我通常将“单入口单出口”或至少其单出口部分视为“崇拜”编程。我只是将“中断,继续和退出”视为工具箱中的工具;我在使代码易于理解的地方使用它们,而在不使代码难以阅读的地方不使用它们。

–梅森·惠勒
2011-3-15在21:32

@ bit-twiddler:赞成。我还要补充一点,一旦您可以轻松将其放置在屏幕上,那么多个出口点的麻烦就会大大减少。

–Shog9
2011-3-17在4:52

#3 楼

我不认为他们是坏人。它们不好的想法来自结构化编程的时代。与以下概念有关:函数必须具有单个入口点和单个出口点,即。 e。每个功能仅一个return

如果您的函数很长,并且有多个嵌套循环,那么这很有道理。但是,您的函数应该简短,并且应该将循环及其主体包装成它们自己的简短函数。通常,强制一个函数具有单个退出点可能会导致逻辑混乱。

如果函数很短,则只有一个循环,或者最糟糕的是有两个嵌套循环,并且循环体很短,那么很清楚breakcontinue的作用。同样清楚的是,有多个return语句是做什么的。

这些问题在Robert C. Martin的“清理代码”和Martin Fowler的“重构”中得到了解决。

评论


“使功能变小。然后使它们变小”-Robert C. Martin。我发现这行之有效。每次您在函数中看到需要注释说明其功能的代码块时,请将其包装到带有描述性名称的单独函数中。即使只有几行,甚至只使用一次。这种做法消除了大多数与中断/继续或多次收益有关的问题。

–迪马
2011年3月15日15:13



@Mikhail:循环复杂性通常与SLOC密切相关,这意味着建议可以简化为“不要编写长函数”。

– John R. Strohm
2011-3-19在16:54

单一出口点的想法被广泛误解。从前,函数不必返回其调用者。他们可能会回到其他地方。这通常是用汇编语言完成的。 Fortran为此有一个特殊的构造。您可以传入一个以&符号CALL P(X,Y,&10)开头的语句号,并且在发生错误的情况下,该函数可以将控制权传递给该语句,而不是返回到调用点。

–kevin cline
2011年10月6日在0:42



例如,与Lua一起使用的@kevincline。

– Qix-蒙尼卡(MS)被盗
2014年12月1日,下午3:41

@cjsimon,你明白了。不仅功能应该很小。班级也应该很小。

–迪马
18年6月1日在20:27

#4 楼

糟糕的程序员讲的是绝对的(就像Sith一样)。优秀的程序员可能会使用最清晰的解决方案(在所有其他条件不变的情况下)。

频繁使用break和continue会使代码难以遵循。但是,如果替换它们使代码更加难于遵循,那将是一个糟糕的更改。

您给出的示例肯定是一种情况,其中断断续续应替换为更优雅的内容。

评论


是的,我夸大了条件的数量,以提供退出案例的例子。

–米哈伊尔
2011-3-15在19:17

您建议的替换代码示例是什么?我认为这是守卫声明的相当合理的例子。

–simgineer
2015年8月5日在20:12



在我看来,“可能的最清晰解决方案”总是……可能吗?怎么可能没有“最清晰”的解决方案?但是,我不是绝对主义者,所以也许你是对的。

–user251748
17年6月6日在18:29

@nocomprende我不确定你在说什么。这里的“可能”并不表示不存在最佳解决方案-只是完美,最终的清晰度不是问题。毕竟这是主观的。

–马修·雷德(Matthew Read)
17年6月6日在18:48



我想看看还有什么更优雅的替代品。我已经编程了一段时间,我很茫然。

–phorgan1
6月16日4:53

#5 楼

大多数人认为这是个坏主意,因为这种行为不容易预测。如果您正在阅读代码,并且看到while(x < 1000){},则假定它将一直运行到x> = 1000为止。但是如果中间有中断,那将不成立,因此您无法真正信任您循环播放...

这是人们不喜欢GOTO的相同原因:当然,它可以很好地使用,但它也可能导致令人讨厌的意大利面条式代码,该代码从部分随机跳转到另一部分。部分。

对于我自己来说,如果我要执行一个在多个条件下中断的循环,我会执行while(x){},然后在需要中断时将X切换为false。最终结果将是相同的,并且阅读该代码的任何人都将更仔细地研究改变X值的事物。

评论


+1说得很好,而while(notDone){}方法则是+1(如果我可以做另一件事)。

– FrustratedWithFormsDesigner
2011-3-15在15:20

Mikhail:中断的问题是循环的最终条件永远不会简单地放在一个地方。这使得很难预测循环后的后置条件。在这种微不足道的情况下(> = 1000),这并不困难。添加许多if语句和不同级别的嵌套后,确定循环的后置条件将变得非常非常困难。

– S.Lott
2011年3月15日15:46



S.Lott完全用力击中头部。控制迭代的表达式应包括为了继续迭代必须满足的所有条件。

–位旋转器
2011年3月17日14:19

更换休息; x = false;不会使您的代码更清晰。您仍然必须在正文中搜索该语句。并且在x = false的情况下;您必须检查它是否未达到x = true;再向下。

– Sjoerd
2011年3月17日下午14:57

当人们说“我看到x并且我假设y,但是如果您执行z,则该假设不成立”时,我倾向于认为“因此,不要做出这个愚蠢的假设”。许多人会将其简化为“当我看到while(x <1000)时,我认为它将运行1000次”。嗯,即使x最初为零,也有很多原因会导致错误的说明。例如,谁说x在循环中精确地增加了一次,却从未以其他方式修改过?即使按照您自己的假设,仅仅因为x> = 1000的设置并不意味着循环将结束-可能会在检查条件之前将其重新设置在范围内。

–Steve314
2011年10月6日,9:57

#6 楼

是的,您可以[重新]编写没有break语句的程序(或从循环中间执行相同操作的返回值)。但是您可能必须引入其他变量和/或代码重复,这通常会使程序更难以理解。因此,Pascal(编程语言)非常糟糕,特别是对于初学者而言。您的老板基本上希望您使用Pascal的控制结构进行编程。如果Linus Torvalds穿上你的鞋子,他可能会向你的老板展示中指!

有一个计算机科学的结果叫做Kosaraju的控制结构层次,可以追溯到1973年,在Knuth的著作中提到(更多)关于1974年的goto的著名论文。(顺便说一下,David Thornley已经在上面推荐了Knuth的论文。)S. Rao Kosaraju在1973年证明的是,不可能重写所有具有多级程序的程序将深度n中断到中断深度小于n的程序中,而不会引入额外的变量。但是,可以说这仅仅是一个理论上的结果。 (只需添加一些额外的变量?!您肯定可以这样做来取悦您的老板...)

从软件工程的角度来看,更重要的是Eric S于1995年发表的最新论文。罗伯茨(Roberts)题为“循环退出与结构化编程:重新开始辩论”(http://cs.stanford.edu/people/eroberts/papers/SIGCSE-1995/LoopExits.pdf)。罗伯茨总结了他之前其他人进行的一些实证研究。例如,当一组CS101型学生被要求为实现在数组中顺序搜索的函数编写代码时,研究的作者对使用中断/返回/跳转来退出找到元素时的顺序搜索循环:


我还没有找到一个使用[此样式]尝试编写程序的人,该人产生了错误的解决方案。


Roberts还说:


试图解决问题而未使用for循环的显式返回的学生的情况要差得多:在尝试该策略的42名学生中,只有七名设法产生了正确的解决方案。该数字表示成功率不到20%。


是的,您可能比CS101的学生更有经验,但无需使用break语句(或等效地从中途返回/转到循环),最终您将编写代码,尽管名义上结构良好,但在额外的逻辑变量和代码重复方面足够多,有人(可能是您自己)会在尝试遵循老板的编码风格时在其中放入逻辑错误。

我还要在这里说,罗伯茨的论文对于普通程序员来说更容易获得,因此比Knuth的论文读起来更好。它也更短,涵盖了一个狭窄的主题。您甚至可以向老板推荐它,即使他是管理层而不是CS类型。

评论


尽管结构化编程是我多年来的方法,但在最近的几年中,他们在第一时间就有机会完全使用显式退出。这样可以更快地执行,并几乎消除了导致无限循环(挂起)的逻辑错误。

– DocSalvager
2015年10月17日下午13:25

#7 楼

我不考虑使用这两种不良做法中的任何一种,但是在同一个循环中使用过多它们应该重新考虑在循环中使用的逻辑。谨慎使用。

评论


:)是的,我提供的示例是概念性的

–米哈伊尔
2011-3-15在15:04

#8 楼

您给出的示例不需要中断也无需继续:

while (primary-condition AND
       loop-count <= 1000 AND
       time-exec <= 3600) {
   when (data != "undefined" AND
           NOT skip)
      do-something-useful;
   }


我对示例中的4行的“问题”是它们都在同一水平上,但是他们做了不同的事情:有些休息,一些继续...您必须阅读每一行。

在我的嵌套方法中,您越深入,代码就变得越“有用”。

但是,如果深入到内部,您会发现停止循环的原因(除主要条件之外),则可以使用中断或返回。我宁愿使用在顶级条件下测试的额外标志,也不愿使用它。中断/返回更直接;它比设置另一个变量更好地说明了意图。

评论


+1但实际上您的<比较需要为<=才能匹配OP解决方案

– El Ronnoco
11年3月16日在11:39

在大多数情况下,如果一个人太深以至于需要使用中断/返回来管理流控制,那么一个人的功能/方法就太复杂了。

–位旋转器
2011年3月17日14:30在

#9 楼

“坏处”取决于您如何使用它们。通常,只有在循环构造会为我节省无法通过算法重构保存的循环时,才使用中断。例如,循环遍历一个集合以查找具有特定属性值设置为true的项目。如果您只需要知道其中一个项目将此属性设置为true,那么一旦达到该结果,就可以适当地中断以终止循环。

如果使用break不会使代码特别易于阅读,缩短运行时间或以显着方式节省处理周期,那么最好不要使用它们。我倾向于尽可能使用“最低公分母”进行编码,以确保跟随我的任何人都可以轻松查看我的代码并弄清楚发生了什么(我并不总是成功的)。休息减少了,因为它们确实引入了奇数的进/出点。被滥用时,它们的行为可能非常像不合常规的“ goto”语句。

评论


我同意这两点!关于您的第二点-我认为按照我的原始帖子比较容易,因为它的读法像英语。如果您在1条if语句中包含条件组合,那么弄清楚if要执行true将要发生什么几乎是破译。

–米哈伊尔
2011-3-15在15:15

@Mikhail:您提供的示例对于特定的真实感有点无私。如我所见,这些样本清晰,简洁,易于阅读。大多数循环不是那样。大多数循环具有正在执行的某种其他逻辑,并且条件可能更复杂。在这些情况下,中断/继续可能不是最佳用法,因为它会使读取时的逻辑混乱。

–乔尔·埃瑟顿(Joel Etherton)
2011-3-15在15:17



#10 楼

绝对不是...是,使用goto是不好的,因为它会破坏程序的结构,并且很难理解控制流。

但是使用breakcontinue这样的语句绝对是这些天是必需的,根本不被认为是不好的编程习惯。

也不难理解使用breakcontinue时的控制流程。在类似switch的结构中,绝对需要break语句。

评论


自从1981年第一次学习C以来,我就没有使用过“ continue”。这是一种不必要的语言功能,因为continue语句绕过的代码可以由条件控制语句包装。

–位旋转器
2011-3-15在15:24

在这种情况下,我更喜欢使用continue,因为这样可以确保我的代码不会变成箭头代码。我比goto类型语句更讨厌箭头代码。我也将其读为:“如果此语句为真,则跳过此循环的其余部分,并继续下一次迭代。”它在for循环的开始时非常有用(在while循环中不太有用)。

–jsternberg
2011-3-15在15:48

@jsternberg为胜利! :-)

–Notinlist
2012年9月26日在12:24

#11 楼

基本概念来自能够对程序进行语义分析。如果您只有一个入口和一个出口,则表示可能状态的数学要比管理分支路径容易得多。

在一定程度上,这一困难反映出在概念上能够做到的问题。您的代码的原因。

坦白说,您的第二个代码并不明显。到底在做什么是继续“继续”,还是“下一步”循环?我不知道。至少您的第一个例子很清楚。

评论


当我在一个项目中经理需要使用它们时,我不得不使用流程图来记住它的使用,并且几个退出路径确实使代码更加混乱。

–umlcat
2011年3月15日18:15

您的“坦率”评论是句法上的-“下一个”是perl的东西;正常语言使用“继续”来表示“跳过此循环”

–米哈伊尔
2011-3-15在18:42

@Mik,也许“跳过此迭代”会是一个更好的描述。真的,您是我先生Pedantic

–彼得·威尔逊(Pete Wilson)
2011年3月15日19:05



@Mikhail:好的。但是,当一种语言使用多种语言工作时,如果两种语言之间的语法不通用,则可能导致错误。

– Paul Nathan
2011-3-15在19:59

但是数学不是编程。代码比数学更具表现力。我知道单次进入/单次退出可能使流程图看起来更好,但付出了什么代价(即在哪里中断/返回可以使代码性能更好)?

–伊文·普莱斯
2011-3-19在7:34

#12 楼

我会用

 while (primary_condition && (loop_count <= 1000 && time_exect <= 3600)) {
    if (this->data != "undefined" && this->skip != true) {
        ..
    }
}
 


代替您的第二个代码片段-出于简洁的原因-我实际上认为这更容易阅读,并且可以让别人了解正在发生的事情。一般而言,循环的条件应完全包含在循环的条件下,而不是在整个身体中乱扔。但是,在某些情况下,breakcontinue可以提高可读性。 breakcontinue多,我可能会加上:D

评论


虽然我不同意“我实际上认为这更易于阅读”,但确实实现了与上述代码完全相同的目的。到目前为止,我还没有真正想到过将“ break”作为短路操作者,但是这很有意义。至于“通常来说,循环的条件应仅包含在那些循环条件之内”,在处理foreach循环时您会怎么做,因为实际上没有办法在循环定义中插入条件逻辑?

–伊文·普莱斯
2011-3-26在8:56

@Evan该条件不适用于foreach循环,因为这只会迭代集合中的每个项目。 for循环的相似之处在于它不应具有条件终点。如果确实需要条件端点,则需要使用while循环。

– El Ronnoco
2011年7月25日下午13:06

@Evan我确实明白你的意思-即“如果需要打破foreach循环该怎么办?” -好吧,从循环来看,我认为最多只能有一个突破。

– El Ronnoco
2011年7月25日13:10

#13 楼

我不同意你的老板。在适当的地方可以使用breakcontinue。实际上,将理解和异常处理引入现代编程语言的原因是,仅使用structured techniques并不能解决所有问题。

在旁注
我不想在这里开始进行宗教讨论,但您可以将代码的结构重组为更具可读性,例如:

 while (primary_condition) {
    if (loop_count > 1000) || (time_exect > 3600) {
        break;
    } else if ( ( this->data != "undefined") && ( !this->skip ) ) {
       ... // where the real work of the loop happens
    }
}
 


另一方面,我个人不喜欢在条件条件中使用( flag == true ),因为如果变量已经是布尔值,那么您将引入一个额外的比较,当布尔值时需要进行比较拥有您想要的答案-除非您当然可以确定编译器将优化额外的比较。

评论


我已经为这个问题困扰了多年。您的方式('if(flag){...}')更为简洁,也许看起来更像'professional'或'expert'。但是,您知道,这通常意味着读者/维护者必须短暂打断自己才能回忆起构造的含义。并确保测试的意义。目前,我正在使用'if(flag == true){...}',只是因为它似乎是更好的文档。下个月?皇后莎贝?

–彼得·威尔逊(Pete Wilson)
2011-3-15在19:02



@Pete-这个词不是简洁但优雅。您可以随意安排所有内容,但是如果您担心读者/维护者不了解布尔值是什么,或者简洁/优雅的术语意味着什么,那么也许您最好雇用一些更聪明的维护者;-)

– Zeke Hansell
2011-3-15在19:30



@Pete,我也支持有关生成代码的声明。通过在计算表达式的布尔值之前将标志与常量值进行比较,可以进行另一次比较。为什么要使难度变得比必需的困难,flag变量已经具有所需的值!

– Zeke Hansell
2011-3-15在19:33

+1好工作。绝对比以前的示例优雅得多。

–伊文·普莱斯
2011-3-19在7:36

#14 楼

我同意你的老板。它们之所以不好是因为它们产生的方法具有很高的环复杂性。这种方法难以阅读且难以测试。幸运的是,有一个简单的解决方案。将循环体提取到单独的方法中,其中“继续”变为“返回”。 “ Return”更好,因为“ return”结束之后-不必担心本地状态。

对于“ break”,将循环本身提取到一个单独的方法中,将“ break”替换为“ return” ”。

如果提取的方法需要大量参数,则表明提取一个类-将它们收集到上下文对象中。

#15 楼

我认为这是一个深深嵌套在多个循环中的问题。很难知道您要进入哪个循环。继续执行可能也很困难,但是我认为真正的痛苦来自于中断-逻辑可能难以遵循。

评论


实际上,很容易看出您是否正确缩进,内部化了这些语句的语义并且不太困。

–user7043
2011年3月15日14:56

@delnan-有很多假设;)

– davidhaskins
2011年3月15日14:56

是的,尤其是最后一个。

– Michael K
2011-3-15在14:57

好吧,无论如何,#1都是认真编程所必需的,#2应该被称为程序员的每个人所期望,并且#3通常非常有用;)

–user7043
2011-3-15在14:57

某些语言(仅我所知道的脚本)支持第2个中断。对于其他人,我想使用临时布尔标志

–米哈伊尔
2011年3月15日15:03

#16 楼

只要不像下面的示例那样将它们用作伪装的goto:

 do
{
      if (foo)
      {
             /*** code ***/
             break;
      }

      if (bar)
      {
             /*** code ***/
             break;
      }
} while (0);
 


我对他们很好。 (示例在生产代码中显示),

评论


您会建议在这种情况下创建函数吗?

–米哈伊尔
2011年3月28日在17:03

是的,如果不可能的话,简单地转到。当我看到一个动作时,我认为是重复,而不是上下文来模拟跳跃。

– SuperBloup
2011年3月29日在8:18

哦,我同意,我只是问你要怎么做:)计算机科学家反复这样做

–米哈伊尔
2011年3月29日14:09

#17 楼

我不喜欢这两种风格。这就是我想要的:



 function verify(object)
{
    if not (object->value < 0) 
       and not(object->value > object->max_value)
       and not(object->name == "") 
       {
         do somethign important
       }
    else return false; //probably not necessary since this function doesn't even seem to be defined to return anything...?
}
 


我真的不喜欢使用return中止功能。感觉像是滥用return一样。

使用break也不总是很容易阅读。

更好的可能是:

 notdone := primarycondition    
while (notDone)
{
    if (loop_count > 1000) or (time_exect > 3600)
    {
       notDone := false; 
    }
    else
    { 
        skipCurrentIteration := (this->data == "undefined") or (this->skip == true) 

        if not skipCurrentIteration
        {
           do something
        } 
        ...
    }
}
 


更少的嵌套和将复杂的条件重构为变量(显然,在实际程序中,您必须具有更好的名称...)

(以上所有代码均为伪代码)

评论


与我在上面键入的内容相比,您真的更喜欢3级嵌套吗?

–米哈伊尔
2011-3-15在15:02

@Mikhail:是的,否则我会将条件的结果分配给变量。我发现比中断并继续的逻辑容易理解的多。异常结束循环感觉很奇怪,我不喜欢它。

– FrustratedWithFormsDesigner
2011-3-15在15:05

具有讽刺意味的是,您误解了我的条件。继续表示跳过功能,进入下一个循环;不是“继续执行”

–米哈伊尔
2011-3-15在15:19

@Mikhail:啊。我不经常使用它,当我阅读它时,我对含义感到困惑。我不喜欢的另一个原因。 :P给我一点时间更新...

– FrustratedWithFormsDesigner
2011-3-15在15:27

太多的嵌套会破坏可读性。有时,避免中断/继续会导致在条件测试中反转逻辑的必要性,这可能导致对代码正在执行的操作产生误解-我只是在说

– Zeke Hansell
2011-3-15在18:45

#18 楼

否。这是解决问题的一种方法,还有其他解决方法。

当前许多主流语言(Java,.NET(C#+ VB),PHP,编写自己的语言)都使用“中断”和“继续”以跳过循环。它们都是“结构化的goto”句子。

没有它们:



 String myKey = "mars";

int i = 0; bool found = false;
while ((i < MyList.Count) && (not found)) {
  found = (MyList[i].key == myKey);
  i++;   
}
if (found)
  ShowMessage("Key is " + i.toString());
else
  ShowMessage("Not found.");
 


和他们在一起:

 String myKey = "mars";

for (i = 0; i < MyList.Count; i++) {
  if (MyList[i].key == myKey)
    break;
}
ShowMessage("Key is " + i.toString());
 


请注意,“ break”和“ continue”代码较短,通常将“ while”语句转换为“ for”或“ foreach”语句。

两种情况都与编码风格有关。我不想使用它们,因为冗长的样式使我可以更好地控制代码。

我实际上是在某些项目中工作的,在这些项目中必须使用这些句子。

一些开发人员可能认为,如果我们不得不删除这些句子,则不一定是必要的,而是假设的它们,我们还必须删除“ while”和“ do while”(“直到您重复,直到重复”);-)

结论,即使我不想使用它们,我也认为一个选择,不是不好的编程习惯。

评论


对不起,很抱歉,但是您的第二个示例缺少未找到键的输出(因此,它看起来短得多了)。

– FrustratedWithFormsDesigner
2011-3-15在18:10

更不用说第一个示例仅在键是列表中的最后一个键时才有效。

–米哈伊尔
2011-3-15在18:41

完全是@FrustratedWithFormsDesigner。我提出理由来说明为什么该方法更可取;-)

–umlcat
2011-3-15在23:09

但是,您有两个具有不同语义的例程。因此,它们在逻辑上并不等效。

–位旋转器
11 Mar 17 '11 at 14:48

您的第二个示例有两个错误,一个是语法错误,另一个是逻辑错误。 1.它不会编译,因为没有在for循环的范围之外声明迭代器(因此在字符串输出中不可用)。 2.即使迭代器是在循环外部声明的,如果在集合中未找到键,则字符串输出也会打印列表中最后一项的键。

–伊文·普莱斯
2011-3-19在7:40



#19 楼

我原则上不反对continuebreak,但是我认为它们是非常底层的结构,通常可以用更好的东西来代替。

我在这里以C#为例,考虑要迭代一个集合的情况,但是我们只希望满足某些谓词的元素,并且我们最多只希望进行100次迭代。



 for (var i = 0; i < collection.Count; i++)
{
    if (!Predicate(item)) continue;
    if (i >= 100) break; // at first I used a > here which is a bug. another good thing about the more declarative style!

    DoStuff(item);
}
 


这看上去很干净。这不是很难理解。我认为从声明性的角度来看会有所收获。将它与以下内容进行比较:

 foreach (var item in collection.Where(Predicate).Take(100))
    DoStuff(item);
 


也许“ Where and Take”调用甚至不应该用这种方法。也许应该在将集合传递给此方法之前完成此过滤。无论如何,通过远离低级内容,而将更多的精力放在实际的业务逻辑上,可以更加清楚地了解我们真正感兴趣的内容。将我们的代码分成更能遵循良好设计规范的内聚模块变得更加容易,因此上。

代码的某些部分中仍然会存在低级内容,但是我们希望尽可能地将其隐藏起来,因为需要花大量精力来进行业务推理。问题。

#20 楼

我只引用代码完成:

在循环的顶部使用Continue进行测试。继续的一个很好的用法是在顶部测试条件之后将执行移到循环的主体之外。例如,如果循环读取记录,丢弃一种记录并处理另一种记录,则可以在循环的顶部进行这样的测试。
以这种方式继续使用可以避免if测试这将有效地缩进循环的整个主体。另一方面,如果继续发生在循环的中间或结尾,请使用和代替。


#21 楼

Code Complete在关于使用goto和例程或循环中的多个返回的内容中有一个不错的部分。

一般来说,这不是一个坏习惯。 breakcontinue准确说明下一步会发生什么。
我也同意。

Steve McConnell(代码完成作者)使用了几乎与您相同的示例来展示使用各种goto语句的优势。

但是过度使用breakcontinue可能会导致软件复杂且无法维护。