本文转载自公众号「脑子进煎鱼了」

最近在冲浪的时候,看到 Redhat 首席软件工程师、Prometheus 等项目的维护者 Bartłomiej Płotka 在 twitter 上出了一道 Go 的 “考题”,说是要来考考大家。

题目如下:

func aaa() (done func(), err error) {return func() { print("aaa: done") }, nil
}func bbb() (done func(), _ error) {done, err := aaa()return func() { print("bbb: surprise!"); done() }, err
}func main() {done, _ := bbb()done()
}

答案的选项如下:

想想原因,思考一下输出结果是什么?是 A,还是 D?还是三短一长,选 B?

分析程序

缩小范围,核心关注到这块代码。如下:

func bbb() (done func(), _ error) {done, err := aaa()return func() { print("bbb: surprise!")done() }, err
}

在最后一行的这个闭包(匿名函数)中,大家可能认为程序调用了函数 aaa 所返回的 done 值来输出程序,应当是:

aaa: done

这个想法是错误的,程序没有这么去运作。

原因在于 return 实际上是一个赋值语句。结合程序,可以看到函数 bbb 的第一个返回值是 done 参数。

如下:

func bbb() (done func(), _ error)

也就是在函数 bbb 在程序最后执行 return 语句后,会对返回变量 done 进行赋值,自然该值不会是由函数 aaa 所设置的了。

这是一个关键的地方。

具体过程

这个程序输出结果是什么呢?

会不断地递归,疯狂输出 “bbb: surprise!”,直至栈溢出,导致程序运行出错,最终中止

同学就疑惑了,怎么又多出了个递归?

我们再看看程序:

func main() {done, _ := bbb()done()
}func bbb() (done func(), _ error) {...return func() { print("bbb: surprise!"); done() }, err
}

本质上在函数 bbb 执行完毕后, 变量 done 已经变成了一个递归函数。

递归的过程是:函数 bbb 调用变量 done 后,会输出 bbb: surprise! 字符串,然后又调用变量 done。而变量 done 又是这个闭包(匿名函数),从而实现不断递归调用和输出。

最终结果如下:

b: surprise!bbb: surprise!bbb: surprise!runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0xc0200e0380 stack=[0xc0200e0000, 0xc0400e0000]
fatal error: stack overflowruntime stack:
runtime.throw(0x1074b5a, 0xe)/usr/local/Cellar/go/1.16.6/libexec/src/runtime/panic.go:1117 +0x72
runtime.newstack()/usr/local/Cellar/go/1.16.6/libexec/src/runtime/stack.go:1069 +0x7ed
runtime.morestack()/usr/local/Cellar/go/1.16.6/libexec/src/runtime/asm_amd64.s:458 +0x8f
...

也就是正确答案是:D,程序最终运行出错。

一直调用一直爽,直至栈溢出程序崩溃。

总结

这位大佬出的题目,本质上是比较烦人的,其结合了函数返回参数的命名用法。

如果我们把这个函数的返回参数命名去掉,就可以避开这个问题。如下:

func bbb() (func(), error) {...return func() { print("bbb: surprise!"); done() }, err
}
...

输出结果为 "bbb: surprise!"。

很多 Go 的同学在日常代码编写的时候不会用到或注意到。但如果写的时候有类似案例代码中的模式,就会排查许久都查不到。

这是个有警惕意义的题目,你觉得呢?

参考

  • twitter 上的原题目

  • Go 语言返回值是引用时return后省略是推荐写法吗?

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

这道 Go 题目外网超过 80% 的人都答错了,你来试试...相关推荐

  1. 学任何东西,你能坚持前三天,就至少超过一半的人,坚持到一周,就可以超过 80% 的人...

    学任何东西,你能坚持前三天,就至少超过一半的人,坚持到一周,就可以超过 80% 的人.这只是参与学习的群体,而剩余的大多数,根本没有参与到学习过程里来. 学一门新技术对有相关经验的人来说入门只需要一周 ...

  2. 两个半小时,一份Python基础试卷,满分100,却有80%的人都不及格

    两个半小时,一份Python基础试卷,满分100,却有80%的人都不及格 Python基础类型考试题 考试时间:90分钟 满分100(80分以上为及格) 如果不给你答案的话,你能及格? 1.件数变量命 ...

  3. 苹果手机小技巧大全计算机,80%的人都不知道的五个iPhone实用小技巧,不知道的话赶紧看看...

    原标题:80%的人都不知道的五个iPhone实用小技巧,不知道的话赶紧看看 现在越来越多的人使用iPhone手机,而且iPhone新机也是出了一段时间了,但是还是有很多人不知道iPhone中的一些隐藏 ...

  4. u盘提示格式化怎么修复?80%的人都在这么做!

    u盘是我们平时经常使用的一个存储设备,使用时间久了容易出现格式化的情况,而这种情况一般都会出现在 U盘上.如果出现格式化的提示,u盘提示格式化怎么修复?很多小伙伴们可能都不知道恢复的方法,今天我们就一 ...

  5. 80%的人都关注的电子合同签署疑问,君子签官方解答来了!

    电子合同签错了在平台可以撤回吗?如果合同上名字签错了,有法律效力吗?签的电子合同,内容会不会被别人看见?- 最近,小编将80%的人都关注的电子合同签署问题进行了整理,官方专业解答帮助大家更好地理解电子 ...

  6. 据说80%的人都不懂,你会控制你的债务吗?

    我们每个人都会有债务,大一点不就是房贷,车贷,或者消费贷款.小一点的比如花呗,信用卡啥的.其实理财的修炼之道里面,不光是要学会赚钱,还要会合理的控制你的债务,债务也是非常重要的一环.开源节流,这个节流 ...

  7. 腾讯云轻量应用服务器 CentOS7.6 +Tomcat/apache 搭建个人web项目,并允许外网通过80或8080端口访问【超详细】

    目录 1. 腾讯云购买学生轻量应用服务器 2. 为服务器用户设置密码允许远程登录 3. 本地下载Xshell和Xftp远程管理更方便 4. 域名认证和域名解析 5. 服务器安装JDK和Tomcat 6 ...

  8. 内网ip映射到外网软件80全端口映射

    内网ip映射到外网,内网ip映射外网,内网映射外网,内网映射到外网,内网ip映射到外网软件-- 当没有公网IP时,或80端口被封,或80端口被屏蔽时,就需要用将内网映射外网,相关网络辅助解决.如NAT ...

  9. 网络知识:路由器要不要每天重启?很多人都做错了,难怪网速慢

    家里用的路由器 长时间运行容易出现网络卡顿现象 很多人习惯重启下 甚至还有人专门关掉路由器让其休息一下 那么路由器到底要不要关? 多久关一次? 路由器到底关不关? 问过很多朋友,很多人都说家里装的路由 ...

最新文章

  1. HDU 1084 - What Is Your Grade?
  2. 2012年4月当选微软MVP的CSDN会员名单揭晓!
  3. 动态规划——双11既可以薅羊毛还能花钱最少
  4. Servlet容器和IOC容器
  5. 达梦数据库角色、用户管理
  6. java.sql.SQLException: sql injection violation, syntax error: TODO QUES
  7. Eli Lilly(礼来) | RPA在医疗行业的应用案例
  8. python node.js ruby_Python/Ruby/Node.js/Perl - 随笔分类 - bluefrog - 博客园
  9. Verilog除法器(32位无符号+带符号)
  10. 【简易爬虫】找回B站“已失效视频”的相关信息
  11. python matplotlib jupyter中绘图使用宋体
  12. CouchDB系列 - 安装CouchDB
  13. 视频压缩编码基本原理
  14. 2022-2027年中国数据银行市场竞争态势及行业投资前景预测报告
  15. SAR图像相干斑滤波算法
  16. 真三国无双3 己方士气提升
  17. React框架简介(JSX语法、组件、虚拟DOM渲染)
  18. 从零开始学运算放大器笔记一 | 认识运算放大器
  19. 从0开始,手把手教你使用React开发答题App
  20. 整合产业链是关键——关于开放平台的一些思考

热门文章

  1. 超好用的webssh(支持秘钥登录)
  2. Percona XtraBackup User Manual 阅读笔记
  3. 第13-17章阅读后的思考
  4. centOS 7下安装与配置heartbeat高可用集群
  5. 关于游戏小说与学习知识的不同
  6. web前端的渐进增强式开发模型
  7. php中将SimpleXMLElement Object数组转化为普通数组
  8. 一个比较完善的购物车类
  9. LeetCode 91. 解码方法
  10. Django基础-Web框架-URL路由