大家好,我是煎鱼。

Goto 语句在社区的讨论中经常被人诟病,认为其破坏了结构化编程和程序的抽象,是有害的,可怕的,是一种糟粕。

最早的观点来源于 1968 年,Edsger Dijkstra 写了一封信《Go To Statement Considered Harmful[1]》,来表达其是有害的观念。

如下图:

不过,但是,其实...

Go 支持了 goto 语句,很多人不理解,大喊 less is more 的 Go Team 居然加了...

今天就由煎鱼带大家看看。

Goto 语法

Goto 的语法格式,如下:

goto label
...
...
label: statement

代码案例,如下:

package mainimport "fmt"func main() {learnGoTo()
}func learnGoTo() {fmt.Println("a")goto FINISHfmt.Println("b")
FINISH:fmt.Println("c")
}

上述代码在函数 learnGoTo 中先输出了 a,然后到了 goto FINISH 代码段,因此直接跳到了 c 的输出,所以 b 的输出代码被直接跳过。

输出结果:

a
c

Goto 的危害

Goto 的危害所带来的一个经典名称是:Spaghetti code[2](意大利面条代码),指的是对非结构化和难以维护的源代码的贬义词。

这样的代码具有复杂而纠结的控制结构,导致程序流程在概念上就像一碗意大利面,扭曲和纠结。

参考代码如下:

INPUT "How many numbers should be sorted? "; TDIM n(T)FOR i = 1 TO TPRINT "NUMBER:"; iINPUT n(i)NEXT i'Calculations:C = TE180:C = INT(C / 2)IF C = 0 THEN GOTO C330D = T - CE = 1I220:f = EF230:g = f + CIF n(f) > n(g) THEN SWAP n(f), n(g)f = f - CIF f > 0 THEN GOTO F230E = E + 1IF E > D THEN GOTO E180GOTO I220C330:PRINT "The sorted list is"FOR i = 1 TO TPRINT n(i)NEXT i

上面这个例子,你能看到 goto 语句能够在任意控制流中到处流转,你可能还得记住它的标签是什么,跳到哪里。

程序员还要起出各种名字,例如:煎鱼哥哥、煎鱼弟弟、煎鱼朋友。起名的灵感是贫乏的,很容易混乱。

真实世界中长期发展的业务代码,滥用 goto 语句可能会更严重。

Goto 存在的意义

Go Spec

实际上在 Go 中,Goto 语句与其他语言相比有着更加严格的限制,在 Go Spec 《Goto statements[3]》 中进行了用法的说明。

规范要求在 goto 语句的作用域范围内不能有任何变量声明等动作,是坏味道。

如下代码:

goto L  // BADv := 3
L:

因为这会导致变量 v 的声明被跳过。

同时要求代码块外的 goto 语句不能跳转到另外一块代码块内的标签。

如下代码:

if n%2 == 1 {goto L1
}
for n > 0 {f()n--
L1:f()n--
}

不能从 if 代码块横跨作用域到 for 代码块。

Go 标准库源码例子

可以看看 Go 标准库中的 math/gamma.go 源代码,是一个很不错的案例。

如下代码:

for x < 0 {if x > -1e-09 {goto small}z = z / xx = x + 1}for x < 2 {if x < 1e-09 {goto small}z = z / xx = x + 1}if x == 2 {return z}x = x - 2p = (((((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 / qsmall:if x == 0 {return Inf(1)}return z / ((1 + Euler*x) * x)
}

自上而下观察观察代码时,能够更快的识别到 goto 语句,并看到下方的标签跳转处,在实现和可读性上都是可以接受的。

意义

说到这里,有的同学可能会发现。出问题,更多是在没有限制的情况下,那 goto 到处乱飞,当然是不合理的。

图来自网络

但这其实又两派观点,就如我们之前文章的读者所提到:

可以怪程序员写出意大利面条,也可以寄望语言层面规避,这样可以做的更好,不需要每一个新来的程序员都要重新培养意识。

Go 也会在 break 中支持标签跳转,与 goto 的用法是相似的:

Loop:for {select {...break Loop}}

Go Team 显然选择了语言层面去规避 goto 的部分复杂场景,约束了只能在一个代码块进行 goto 跳转,这样能够拥有更好的可读性,也能得到相应的价值。

总结

一个新的关键字的产生,必然包含其背景的原因和行为。如果只是一味地一刀切,最后肯定会解决了个寂寞。

经过这近 60 年的计算机行业的 goto 知识熏陶和思考,大家已经认识到 goto 在任意控制流中乱跳是非常恶心的。包括世界上最好的语言 PHP,其实在 5.3.0 起,也慎重的加入了 goto,也是带限制的,范围是同一个文件和作用域。

新的 goto 形态,是这种带限制的 goto 模式的探索。你觉得怎么样?

If you need to go to somewhere, goto is the way to go. —— Ken Thompson

参考资料

[1]

Go To Statement Considered Harmful: https://dl.acm.org/doi/10.1145/362929.362947

[2]

Spaghetti code: https://en.wikipedia.org/wiki/Spaghetti_code

[3]

Goto statements: https://go.dev/ref/spec#Goto_statements

关注煎鱼,获取业内第一手消息和知识

goto 语句到底坑不坑?相关推荐

  1. C++ break语句,continue语句,goto语句

    break 语句的作用: 跳出当前循环,中断当前循环 #include <iostream> using namespace std; int main() {for (int i = 0 ...

  2. SQL Server-流程控制 5,Goto 语句

    ylbtech-SQL Server:SQL Server-流程控制 5,Goto 语句 SQL Server 流程控制中的 Goto 语句. 1,Goto 语句 1 --============== ...

  3. 两种方式(goto语句以及while循环)实现C语言关机小程序

    用C语言写的关机小程序简单易懂,可以拿去整蛊室友同学(每天一个挨打小技巧),下面我就给出两种方式实现这个代码,欢迎大家讨论补充. 1.用goto语句实现: #include <stdio.h&g ...

  4. C#基础系列问题一break、continue、return、goto语句

    一.break     1. break语句形式: break;     2. break语句功能:        A. 在switch语句中,break是其语法本省的一部分,break语句会终止其后 ...

  5. C语言goto语句的使用

    不使用goto语句: 使用goto语句: 使用goto语句时需要注意以下原则: 1) 不要过份地使用.比如图2中的60行就没有采用goto语句跳到程序的最后面,之所以这里不使用goto是为了阅读方便. ...

  6. c语言goto语句用法_C语言中的goto语句该不该使用?

    关于C语言的goto语句存在很多争议,很多书籍都建议"谨慎使用,或者根本不用".这里先不做过多的讨论,存在即合理,既然是C语言中的一个知识点,我们还是有必要学会使用.先看一些got ...

  7. 使用if和goto语句构造循环

    goto是C/C++中一种非常古老的保留字,goto语句也称为无条件转移语句,其一般格式如下: goto 语句标号: 其中语句标号是按标识符规定书写的符号, 放在某一语句行的前面,标号后加冒号(:). ...

  8. php 常量 循环 1,php循环控制break、continue语句、goto语句和php常量

    1.循环控制break语句: break结束当前 for,while,do-while 或者switch 结构的执行. Break可以接受一个可选的数字参数来决定跳出几重循环. $i = 0; whi ...

  9. 《Java 7程序设计入门经典》一3.14 像使用goto语句一样使用break语句

    3.14 像使用goto语句一样使用break语句 除了用于switch语句和循环外,break语句也可以用提供像goto语句一样的用法.由于goto语句是一种改变程序流的非结构化方法,因此Java并 ...

最新文章

  1. JDBC批处理读取指定Excel中数据到Mysql关系型数据库
  2. 2019已过半,薪资相匹配除了实力,其实最重要的是……
  3. CodeForces 780 E Underground Lab
  4. 你们公司内部有WiKi么
  5. 谷粒商城RabbitMQ锁库存逻辑详解--新理解(长文警告)
  6. 手机卫士09_应用程序四种查看_ListView小标题_进程管理
  7. 安防监控系统CIF、D1等格式的解释
  8. java dumpheap_java程序性能分析之thread dump和heap dump
  9. 基于 Flink 的典型 ETL 场景实现
  10. 成绩排序(信息学奥赛一本通-T1178)
  11. 多模态大咖齐刷刷翻开小红书,明晚7点不见不散
  12. 洛谷P3378 【模板】堆
  13. 百度和bing的背景肤色图片的保存
  14. 56相册视频(土豆相册视频 激动相册视频 QQ动感影集等)——下载教程
  15. 马哥python_马哥Python 开发9期
  16. DMA控制器8237A
  17. android格式化SD卡,获取其它程序的缓存大小,清理数据
  18. 独家整理: 六款高质量的办公资源网站,疯狂提高你的工作效率
  19. Ai智能对话页面html,js人工智能对话框 - osc_q50is30g的个人空间 - OSCHINA - 中文开源技术交流社区...
  20. 华为云王红新_华为云新加坡峰会多家公司签署MoU,伙伴联合展示云+AI创新应用...

热门文章

  1. session的删除
  2. SQL注入_Bypass安全狗apache主程序版本v4.0.23137绕过
  3. 人事管理系统:HR手机版__WeOrg 组织人事小程序
  4. NOIP模拟赛 四校联考 递推 + 分类讨论 + 树上期望
  5. 生命值c语言编码怎么打,【图片】初学C语言 麻烦大佬们帮帮忙【c语言吧】_百度贴吧...
  6. uniapp实现微信小程序全局【发送给朋友】、【分享到朋友圈】、【复制链接】
  7. 生活随记 - 孩子教育
  8. Jenkins配置任务
  9. 天人合一道法自然的注解_道法自然 天人合一
  10. 天人合一道法自然的注解_什么是“天人合一”?这才是“道法自然”的真谛!...