每个人都知道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语句就像告诉木匠不要使用锤子,因为锤子在钉钉子的时候可能会损坏墙壁。真正的程序员知道如何以及何时使用GOTO。我跟随了一些所谓的“结构化程序”,我看到过这样可怕的代码,只是为了避免使用GOTO,我可以射杀程序员。好吧,为另一方辩护,我也见过一些真正的意大利面条代码,同样,那些程序员也应该被枪毙。

下面是我找到的一个小代码示例。

  YORN = ''
  LOOP
  UNTIL YORN = 'Y' OR YORN = 'N' DO
     CRT 'Is this correct? (Y/N) : ':
     INPUT YORN
  REPEAT
  IF YORN = 'N' THEN
     CRT 'Aborted!'
     STOP
  END

----------------------- 或 ----------------------

10:  CRT 'Is this Correct (Y)es/(N)o ':

     INPUT YORN

     IF YORN='N' THEN
        CRT 'Aborted!'
        STOP
     ENDIF
     IF YORN<>'Y' THEN GOTO 10

其他回答

我避免使用它,因为同事/经理无疑会在代码评审或偶然发现它时质疑它的使用。虽然我认为它有一些用途(例如错误处理案例),但你会遇到一些其他开发人员,他们会遇到一些类型的问题。

这不值得。

一个现代的GOTO用法是由c#编译器为yield return定义的枚举器创建状态机。

GOTO应该由编译器而不是程序员使用。

我的一个同事说,使用GOTO的唯一原因是,如果你把自己逼到了绝境,这是唯一的出路。换句话说,提前进行适当的设计,以后就不需要使用GOTO了。

我认为这幅漫画很好地说明了“我可以重构程序的流程,或者用一个小的‘GOTO’来代替。”当你的设计不完善时,GOTO是一种不完善的方法。迅猛龙捕食弱者。

直到C和c++(以及其他罪魁祸首)标记了断点和继续,goto将继续发挥作用。

在一个完美的世界里,我们永远不需要GOTO。然而,我们生活在一个不完美的世界。我们并没有包含我们所能想到的所有控制结构的编译器。有时我觉得使用GOTO比拼凑一个并不存在的控制结构更好。

最常见的(并不是说它很常见)是循环半结构。你总是执行第一部分,也许你执行剩下的部分,然后返回,再执行第一部分。当然,你可以在while循环中使用布尔标记来实现它,但我不喜欢这个答案,因为在我看来它不太清楚。当你看到这样的东西:

loop:
  GetSomeData;
  if GotData then
     Begin
        ProcessTheData;
        StoreTheResult;
        Goto Loop;
     End;

对我来说,这比

Repeat
  GetSomeData;
  Flag := GotData;
  if Flag then
    Begin
      ProcessTheData;
      StoreTheResult;
    End;
Until Not Flag;

有些时候

Function GotTheData;

Begin
  GetSomeData;
  Result := GotData;
End;

While GotTheData do
  Begin
    ProcessTheData;
    StoreTheResult;
  End;

不是一个可行的答案,我坚信代码应该是清晰的。如果我必须做一个注释来解释代码在做什么,我会考虑是否可以让代码更清晰,并去掉注释。