【发布时间】:2021-10-03 20:59:05
【问题描述】:
这个panic recover code 使用命名的返回值。
func main() {
result, err := foo()
fmt.Println("result:", result)
if err != nil {
fmt.Println("err:", err)
}
}
func foo() (result int, err error) {
defer func() {
if e := recover(); e != nil {
result = -1
err = errors.New(e.(string))
}
}()
bar()
result = 100
err = nil
return
}
func bar() {
panic("panic happened")
}
输出
result: -1
err: panic happened
但是为什么带有局部变量的this code 不起作用呢?
func main() {
result, err := foo()
fmt.Println("result:", result)
if err != nil {
fmt.Println("err:", err)
}
}
func foo() (int, error) {
var result int
var err error
defer func() {
if e := recover(); e != nil {
result = -1
err = errors.New(e.(string))
}
}()
bar()
result = 100
err = nil
return result, err
}
func bar() {
panic("panic happened")
}
输出
result: 0
有什么解释可以帮助我理解它的原因/基本概念吗?在 go tour basics 中解释如下。
命名返回值 Go 的返回值可以命名。如果是这样,它们将被视为在函数顶部定义的变量。
所以应该是一样的吧?
【问题讨论】:
-
你可以得到A -> B,但不能得到B -> A。
-
“所以它应该是一样的,对吧?”,不,对于延迟函数来说根本不是。在第二个示例中,local 变量 err 已更改,但这不会传播回调用者。
-
@Volker:当你的意思是 local 变量
err在第二种情况下,这是否意味着在第一种情况下命名返回,值(结果,错误)做在 main() 中有参考吗?试图了解命名返回如何在后台工作 -
有一种技术方法可以将返回的值传播回调用者:堆栈上的插槽或寄存器或......无关紧要。 Named 返回值允许访问此插槽。命名的返回值仅使用该插槽作为内存。当您执行
return result, err时,err会复制到该插槽中(也是结果),但 err 有它自己的内存。