哈喽,大家好, 今天新注册了
Redhat
的首席工程师、Prometheus
开源项目维护者 Bartłomiej Płotka 发出的,经调查显示,这道题的正确率只有15.2%
,惨目忍睹,接下来我们就一起来看一下这道题~原文地址:https://twitter.com/bwplotka/status/1495002204163678211
下面这段代码输出结果是多少?
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()
}
正确答案是:永远不会结束,你答对了吗?
这道题考查的点就是命名返回值+闭包,把上面的代码换成等效的匿名返回值代码你就明白了:
func aaa() (func(), error) {
var done func()
done = func() {
print("aaa: done")
}
return done, nil
}
func bbb() (func(), error) {
var done func()
done, err := aaa()
done = func() {
print("bbb: surprise!");
done()
}
return done, err
}
func main() {
done, _ := bbb()
done()
}
这其实是Go
语言设计上一个feature
,当Go
语言的返回值赋给我们特殊的"返回参数"时,如果它们被命名了,在return
之后,我们可以在函数主体完成后的任何执行过程中引用那些带有这些名称的值,在defer
或闭包中一样。
我们在说回这道题,在bbb()
函数内我们使用了命名返回值done func(), _ error
,使用短变量声明done, err := aaa()
接收aaa()
的返回值,这里变量done
并不是一个新变量,这就要说到Go
语言的短变量声明的语法糖了,在多变量声明中,如果其中一个变量是新的,可以使用 :=
声明,编译器会进行类型推断和赋值,已经声明的变量不会重新声明,直接在原变量上赋值;之后我们return
的是一个闭包函数,闭包里的done
值并不会被提前解析,在bbb()
函数结束后,实际对应的代码就成了这样,变成了递归。
done = func() {
print("bbb: surprise!");
done()
}
如果我们把代码在改成这样:
func bbb() (func(), error) {
var done func()
done, err := aaa()
return func() {
print("bbb: surprise!");
done()
}, err
}
答案就是:bbb: surprise!aaa: done
一道看似简单的题,其中蕴涵的知识点确有很多,这就说明了解设计原理是多么的重要,Go语言
资深工程师的路上任重道远呀~。
好啦,本文到这里就结束了, 我们下期见。
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8