每个人都知道Dijkstra的《致编辑的信》:goto语句被认为是有害的(这里。html transcript和这里。pdf),从那时起,就有一种强大的推动力,尽可能避免使用goto语句。虽然可以使用goto来生成不可维护的、庞大的代码,但它仍然存在于现代编程语言中。即使Scheme中先进的连续控制结构也可以被描述为复杂的后向。

在什么情况下需要使用goto?什么时候最好避免?

作为一个后续问题:C提供了一对函数setjmp()和longjmp(),它们不仅提供了在当前堆栈帧内进行跳转的能力,还提供了在任何调用帧内进行跳转的能力。这些应该被认为和goto一样危险吗?更危险?


Dijkstra自己也对这个头衔感到后悔,因为这不是他的责任。在EWD1308的结尾(也在这里。pdf),他写道:

Finally a short story for the record. In 1968, the Communications of the ACM published a text of mine under the title "The goto statement considered harmful", which in later years would be most frequently referenced, regrettably, however, often by authors who had seen no more of it than its title, which became a cornerstone of my fame by becoming a template: we would see all sorts of articles under the title "X considered harmful" for almost any X, including one titled "Dijkstra considered harmful". But what had happened? I had submitted a paper under the title "A case against the goto statement", which, in order to speed up its publication, the editor had changed into a "letter to the Editor", and in the process he had given it a new title of his own invention! The editor was Niklaus Wirth.

Donald E. Knuth写了一篇关于这个主题的经典论文,它与Dijkstra的论文相匹配,那就是结构化编程与语句。阅读既有助于重建上下文,也有助于对主题的非教条性理解。在本文中,Dijkstra对这个案例的观点被报道,并且更加强烈:

Donald E. Knuth:我相信通过呈现这样一个 事实上,我并不是不同意 Dijkstra的观点,因为 他最近写道: “请不要落入。 相信我是可怕的 教条的关于[去]的教条的 声明)。我觉得很不舒服 感觉别人在做 宗教出来了,好像 编程的概念问题 只用一个小技巧就能解决,用什么 一种简单的编码纪律!”


当前回答

并不是说去做本身不好;而是当同样的逻辑可以用另一种方式更清楚地表达时,使用goto是不好的。它会使代码很难遵循,也会使维护变得困难。以《糟糕的过去》中的一些Basic程序为例。

在我看来,在像c#这样的现代语言中,我们不应该在正常情况下需要goto。如果我发现自己正在使用它,这通常表明我需要重新思考我的逻辑——几乎肯定有一种更清晰的方式来使用正常的代码流语句来表达相同的代码。

也就是说,对于某些特殊的目的来说,goto是非常有用的(我发现自己对那些没有goto的语言非常恼火)。我主要在C语言中使用它来打破多层循环,或者进行错误处理;我相信c#的语言特性意味着您不必这样做。(它在生成自动生成代码时也非常有用,但大多数人在现实生活中不会遇到这种情况。)

goto还有一个纯粹的政治问题:很多人讨厌它,在代码中使用它,即使是合理的,也可能会引起问题。如果这是作业代码,那么是的,重写它,否则你可能会被扣分。否则,我倾向于把它留在那里,直到下次你需要对那部分进行维护。

其他回答

goto的基本思想是给你太多的自由去做你不想做的事情。它可能在与goto语句无关的地方导致错误,因此使代码维护更加困难。如果你认为你需要一个goto语句,你错了:),你应该重新思考你的代码结构。这就是为什么现代编程语言投入了大量精力来提供可读的、可维护的流控制结构和异常处理机制。

我也不同意拉塞夫克的观点。由于goto被滥用的次数多于正确使用的次数,我相信它在设计良好的语言中没有一席之地。即使对于goto的“理想”用途,其他需要更多代码的方式也应该是首选。

所以总的来说,是的,它仍然被认为是有害的。

GOTO就像台锯,在采取适当的安全措施时非常有用。

我认为这是有害的,因为大多数初学者都失去了桌子锯和goto的手指。

在某些情况下,这是控制心流的唯一方法,但这些情况是可以避免的。

我只记得用过一次goto。我有一系列五个嵌套计数循环,我需要能够根据某些条件从内部打破整个结构:

    for{
      for{
        for{
          for{
            for{
              if(stuff){
                GOTO ENDOFLOOPS;
              }
            }
          }
        }
      }
    }
    
    ENDOFLOOPS:

我可以很容易地声明一个布尔中断变量,并将其用作每个循环的条件的一部分,但在这种情况下,我认为GOTO是一样实用和一样可读的。

没有迅猛龙攻击我。

并不是说去做本身不好;而是当同样的逻辑可以用另一种方式更清楚地表达时,使用goto是不好的。它会使代码很难遵循,也会使维护变得困难。以《糟糕的过去》中的一些Basic程序为例。

在我看来,在像c#这样的现代语言中,我们不应该在正常情况下需要goto。如果我发现自己正在使用它,这通常表明我需要重新思考我的逻辑——几乎肯定有一种更清晰的方式来使用正常的代码流语句来表达相同的代码。

也就是说,对于某些特殊的目的来说,goto是非常有用的(我发现自己对那些没有goto的语言非常恼火)。我主要在C语言中使用它来打破多层循环,或者进行错误处理;我相信c#的语言特性意味着您不必这样做。(它在生成自动生成代码时也非常有用,但大多数人在现实生活中不会遇到这种情况。)

goto还有一个纯粹的政治问题:很多人讨厌它,在代码中使用它,即使是合理的,也可能会引起问题。如果这是作业代码,那么是的,重写它,否则你可能会被扣分。否则,我倾向于把它留在那里,直到下次你需要对那部分进行维护。

Donald E. Knuth在1992年CSLI出版的《识字编程》一书中回答了这个问题。在第17页有一篇文章“使用goto语句的结构化编程”(PDF)。我认为这篇文章也可能发表在其他书中。

本文描述了Dijkstra的建议,并描述了这种建议有效的情况。但他也给出了一些反例(问题和算法),这些反例仅用结构化循环是无法轻易重现的。

这篇文章包含了对问题、历史、例子和反例的完整描述。