goto
普遍不建议这样做。使用此语句是否值得?
goto
不是必需的。这是用命令式语言实现它们的最合理的方法,因为它是最接近状态转换语义的东西。而且它的目的地可能离源头很远,不会妨碍可读性。我最喜欢的代码示例是DE Knuth对Adventure游戏的实现。
goto
普遍不建议这样做。使用此语句是否值得?
goto
不是必需的。这是用命令式语言实现它们的最合理的方法,因为它是最接近状态转换语义的东西。而且它的目的地可能离源头很远,不会妨碍可读性。我最喜欢的代码示例是DE Knuth对Adventure游戏的实现。
Answers:
在Stack Overflow上已经对此进行了数次讨论,Chris Gillum 总结了可能的用法goto
:
干净地退出功能
通常在函数中,您可能会分配资源,并且需要在多个位置退出。程序员可以通过将资源清除代码放在函数的末尾来简化其代码,该函数的所有“退出点”都将进入清除标签。这样,您不必在函数的每个“退出点”都编写清理代码。
退出嵌套循环
如果您处于嵌套循环中并且需要脱离所有循环,那么goto可以比break语句和if-checks更加简洁明了。
低级性能改进
这仅在性能至关重要的代码中有效,但是goto语句执行得非常快,并且在遍历函数时可以助您一臂之力。但是,这是一把双刃剑,因为编译器通常无法优化包含gotos的代码。
我认为,就像在许多其他情况下一样,在所有这些情况下,的用法都goto
被用作摆脱自己编写的代码的手段,并且通常是可重构代码的症状。
finally
现代语言中的块很好地解决,第二个问题可以通过标记为break
s 来解决。但是,如果您坚持使用C,goto
那么这几乎是优雅解决这些问题的唯一方法。
finally
仅在那些条件下有效。在非常罕见但有效的情况下,goto是必经之路。
break 3
or break myLabel
和之间的区别到底是什么goto myLabel
。哦,就是关键字。如果您使用的break
,continue
或一些类似的关键字,您是INFACT使用goto
(如果您正在使用for, while, foreach, do/loop
您使用的是有条件的转到)
更高级别的控制流构造倾向于对应于问题域中的概念。if / else是基于某种条件的决策。循环表示重复执行某些操作。甚至有一个break语句也说:“我们一直在重复这样做,但是现在我们需要停止”。
另一方面,goto语句倾向于对应于正在运行的程序中的概念,而不是问题域中的概念。它说,在指定点继续执行该计划。读取代码的人必须推断出对于问题域的含义。
当然,所有更高级别的构造都可以用gotos和简单的条件分支来定义。这并不意味着它们只是变相的东西。将它们视为受限的对象 -正是这些限制使它们变得有用。break语句的实现是跳转到封闭循环的末尾,但最好将其视为对整个循环的操作。
在所有其他条件相同的情况下,其结构反映问题域结构的代码往往更易于阅读和维护。
在任何情况下,绝对没有必要使用goto语句(有一个这样的定理),但在某些情况下,它可能是最不坏的解决方案。这些情况因语言而异,具体取决于语言支持的高层构造。
例如,在C语言中,我认为有三种适合使用goto的基本方案。
另一方面,还可以在循环内部使用switch语句来实现显式有限状态机。这样做的好处是,每个状态都在代码中的同一位置开始,例如,这对于调试很有用。
goto在一种相当现代的语言(支持if / else和loops的语言)中的主要用途是模拟该语言所缺少的控制流构造。
goto
。SSSM通常是可以使用的良好结构,因为它们将SM状态与执行结构分离开来,但是它们并没有真正消除“困境”。
当然,这取决于编程语言。goto
引起争议的主要原因是,当编译器让您过于自由地使用它时,会产生不良影响。例如,如果它使您goto
以现在可以访问未初始化变量的方式使用,或者更糟糕的是,跳入另一个方法并弄乱了调用堆栈,则可能会出现问题。禁止不必要的控制流是编译器的责任。
Java试图通过goto
完全禁止来“解决”此问题。但是,Java允许您return
在finally
块内部使用,从而导致意外吞下异常。仍然存在相同的问题:编译器没有完成其工作。goto
从语言中删除并不能解决问题。
在C#中,goto
是安全的,因为break
,continue
,try/catch/finally
和return
。它不允许您使用未初始化的变量,不允许您跳出finally块等。编译器会抱怨。这是因为它解决了实际的问题,就像我所说的无意义的控制流程。goto
不会神奇地取消定值分析和其他合理的编译器检查。
goto
不是邪恶的吗?如果是这样的话,那么每一种日常使用的现代语言都具有goto
结构,不仅是C#...
是。当您的循环嵌套在多个级别的深处时,这goto
是优雅地突破内部循环的唯一方法。另一个选择是设置一个标志,如果该标志满足条件,则退出每个循环。这确实很丑陋,而且容易出错。在这些情况下,goto
就是更好。
当然,Java的带标签的break
语句执行相同的操作,但是不允许您跳到代码中的任意点,这可以巧妙地解决问题,而又不会使事情变得goto
邪恶。
Do
循环。为什么?因为我可以将需要深入分解的一个循环更改为一个Do
循环并输入Exit Do
,所以没有GoTo
。嵌套循环一直在发生。打破堆栈的发生率大约为%。
大部分的挫折来自某种形式的“宗教”,它源于Djikstra神,该神在60年代初就因其不分青红皂白的力量而引人注目:
这与goto
现代语言的声明无关,后者的存在仅是由于支持了所提供语言之外的代码结构的创建。
特别是上面的第一个主要点已被允许,第二个主要点已被清除(如果您goto
超出了一个块,则堆栈将正确展开,并调用所有适当的析构函数)
您可以参考此答案,以了解即使不使用goto的代码也难以理解的想法。问题不在于goto本身,而是对它的不良使用。
我可以不使用if
而只编写整个程序for
。当然,它的可读性不佳,外观笨拙且不必要地复杂。
但是问题不是for
。是我。
之类的东西break
,continue
,throw
,bool needed=true; while(needed) {...}
,等被提超过伪装 goto
从Djikstrarian狂热者的弯刀逃逸而去,现代laguages-的发明- 50年后,仍然希望自己的囚犯。他们忘了Djikstra在说什么,他们只记得笔记的标题(GOTO认为这是有害的,甚至连他的头衔都没有:它被编辑器更改了),并且责备bash,bash并责怪每一个拥有这4个内容的结构字母顺序放置。
现在是2011年:是时候该理解不理会Djikstra令人信服goto
的GOTO
声明了。
break n
在C ++中不可用,因此goto escape
,即使escape
不需要从n-ple循环中出来也是如此。
只要在函数中是本地的,这里或那里的奇异goto几乎不会严重损害可读性。它通常会通过吸引人们注意以下事实而受益:该代码中发生了一些不寻常的事情,需要使用某种不常见的控制结构。
如果(local)gotos严重损害了可读性,则通常表明包含goto的函数过于复杂。
我放入一段C代码中的最后一个步骤是构建一对互锁的循环。它不符合“可接受的” goto使用的常规定义,但是最终该功能变得更小,更清晰。为了避免goto,需要特别混乱地违反DRY。
我认为整个问题一直是树桩错误的情况。
这样的GOTO在我看来似乎没有问题,但它通常是一种实际罪过的症状:意大利面条式代码。
如果GOTO导致流量控制线严重交叉,那就不好了。如果没有穿过流量控制线,则无害。在介于两者之间的灰色区域中,我们有循环救助之类的东西,仍然有些语言没有添加涵盖所有合法灰色情况的构造。
我发现自己多年来实际使用过的唯一情况是循环的情况,决策点位于循环的中间。您将剩下重复的代码,标志或GOTO。我发现GOTO解决方案是三者中最好的。这里没有流量控制线的交叉,这是无害的。
goto
s跳入循环的一个著名用例(如果语言允许,则为另一种情况,请跳至不在中间的循环,通常不带goto
)是微不足道的。
goto
高呼控制流不适合正常的结构化编程模式。因为适合结构化编程模式的控制流比不适合结构化编程模式的控制流更容易推理,因此应尽可能尝试使用这种模式。如果代码确实适合这种模式,则不应大声疾呼它不适合。另一方面,在代码确实不适合此类模式的情况下,大喊大叫可能比假装代码不适合时更好。
是的,可以使用goto来丰富开发人员的经验:http : //adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/
但是,就像使用任何强大的工具(指针,多重继承等)一样,必须使用该工具进行训练。链接中提供的示例使用PHP,它将goto构造的用法限制为相同的函数/方法,并且禁用了跳转到新的控制块(例如,循环,switch语句等)的功能。
我会说不。如果您发现需要使用GOTO,我敢打赌,需要重新设计代码。
我会说不。应该始终使用更特定于goto所要解决问题的工具来代替它们(除非您的语言不可用)。例如,break语句和异常解决了先前goto解决的循环转义和错误处理问题。
goto
这些语言通常是不存在的。
goto
最接近问题域语义的东西出现时,其他任何事情都是肮脏的。