为什么Go有一个"goto"声明

har*_*arm 96 goto go

谷歌的Go语言是一种新语言.因此,我惊讶地发现它有一个'goto'声明.我一直被教导说'goto'语句已成为过去,而且它会使程序的实际流程陷入窘境.功能(或方法,如果你愿意)总是一种更好的控制流量的方法.

我肯定错过了什么.为什么以及何时使用'goto'是一个好主意?或者谷歌为什么要加入它?

Kis*_*aki 72

当我们实际检查Gos源代码(标准库)时,我们可以看到gotos实际应用的位置.

例如,在math/gamma.go文件中,使用goto语句:

  for x < 0 {
    if x > -1e-09 {
      goto small
    }
    z = z / x
    x = x + 1
  }
  for x < 2 {
    if x < 1e-09 {
      goto small
    }
    z = z / x
    x = x + 1
  }

  if x == 2 {
    return z
  }

  x = x - 2
  p = (((((x*_gamP[0]+_gamP[1])*x+_gamP[2])*x+_gamP[3])*x+_gamP[4])*x+_gamP[5])*x + _gamP[6]
  q = ((((((x*_gamQ[0]+_gamQ[1])*x+_gamQ[2])*x+_gamQ[3])*x+_gamQ[4])*x+_gamQ[5])*x+_gamQ[6])*x + _gamQ[7]
  return z * p / q

small:
  if x == 0 {
    return Inf(1)
  }
  return z / ((1 + Euler*x) * x)
}
Run Code Online (Sandbox Code Playgroud)

goto从导入只是控制流使用的另一(布尔值)的变量,在端部检查在这种情况下我们节省.在这种情况下,该goto语句使代码实际上更好地阅读和更容易遵循(完全与goto你提到的反对你的论点相反).

另请注意,该goto语句具有非常具体的用例.关于goto语言规范声明它可能不会跳过进入作用域(被声明)的变量,并且它可能不会跳转到其他(代码)块.

  • 在你的例子中,为什么不直接引入函数`small(x,z)`来调用?这样我们就不必考虑`small:`标签中可以访问哪些变量.我怀疑原因是仍然缺乏编译器中某些类型的内联支持. (60认同)
  • @Jessta:这就是我们的可见性和范围,对吗? (5认同)
  • @ThomasAhle Go在引入新变量后不允许`goto`指向标签.[执行"goto"语句不得导致任何变量进入范围,这些变量在goto点已经不在范围内.](https://golang.org/ref/spec#Goto_statements) (5认同)
  • @ ogc-nick对不起我不清楚,我的意思是这些函数可以在需要它们的范围内声明,因此它们对于不需要它们的代码是不可见的.我不是在谈论goto和范围. (4认同)
  • @MosheRevah引用的代码未针对可读性进行优化.它针对原始性能进行了优化,使用在单个函数中跨越22行的goto.(而Thomas Ahle的提议在我看来更具可读性.) (4认同)
  • @Thomas,我很确定这是因为在很多情况下缺乏内联。函数调用很重要的计算密集型应用程序往往包含大量数学内容,因此在 math 包中使用 goto 是相当合理的。 (3认同)
  • 可能值得一提的是,该代码是直接移植到C代码上去的。查看文件顶部的评论。 (3认同)
  • @ThomasAhle 函数意味着重用,一旦你有了一个函数,你在更改它时就必须考虑调用者。 (2认同)
  • @Jessta除了前面的评论之外,我还提出,与大多数商业/工业应用程序代码不同,企业所有者出现并修改伽马功能的要求基本上没有风险.根据我的经验,不得不在不必要的复杂流控制中进行更改是意大利面条代码真正咬了后来的开发人员的地方之一. (2认同)

Son*_*nia 25

当没有任何内置控件功能完全符合您的要求时,当您可以用goto表达您想要的内容时,Goto是一个好主意.(在没有goto的情况下,在某些语言的情况下这是很遗憾.你最终滥用某些控制功能,使用布尔标志,或使用比goto更差的其他解决方案.)

如果某些其他控件功能(以相当明显的方式使用)可以做你想要的,你应该优先使用它来转到.如果没有,请加粗并使用转到!

最后值得注意的是Go的goto有一些限制旨在避免一些模糊的错误.请参阅规范中的这些限制.


Gus*_*tav 10

自60 年代和 70 年代的意大利面条式代码时代以来,Goto 语句受到了很多质疑。当时的软件开发方法非常差。然而,Goto 本身并不是邪恶的,但当然可以被懒惰或不熟练的程序员误用和滥用。许多被滥用的 Goto 问题都可以通过开发流程(例如团队代码审查)来解决。

goto以与continuebreak和相同的技术方式进行跳跃return。人们可能会争辩说,这些陈述以同样的方式是邪恶的,但事实并非如此。

Go 团队之所以包含 Goto,可能是因为它是一个常见的流控制原语。此外,他们希望得出结论,Go 的范围不包括使白痴安全的语言不可能被滥用。

  • `continue`、`break` 和 `return` 在一个关键点上非常不同:它们仅指定“离开封闭范围”。它们不仅鼓励而且明确要求开发人员考虑其代码的结构并依赖[结构化编程](https://en.wikipedia.org/wiki/Structured_programming)原语(for 循环、函数和 switch 语句)。“goto”语句唯一的优点是,当编译器的优化器无法胜任任务时,它们允许您在 HLL 中编写汇编,但这是以可读性和可维护性为代价的。 (2认同)