go 并行赋值与defer的关系
在你提供的代码片段中,涉及了变量作用域和闭包的问题,让我们来分析一下为什么输出的是 error2 而不是 error。
func msg() (result string) {
err := errors.New("error")
defer func() {
fmt.Println(err) // 这里为啥是error2,而不是error?
}()
a, err := "ssss", errors.New("error2") // 这个为啥不会报错?
fmt.Println(a)
return
}
分析:
-
第一部分:
err := errors.New("error")- 这行代码定义了一个名为
err的变量,并赋值为errors.New("error")。
- 这行代码定义了一个名为
-
第二部分:
defer func() { fmt.Println(err) }()- 这里使用了
defer延迟执行函数,它捕获了外部函数的err变量。 - 注意,这里的
defer函数中使用的err是一个闭包,它会在msg()函数返回时执行。在执行时,它捕获的是msg()函数返回时的err变量的值。
- 这里使用了
-
第三部分:
a, err := "ssss", errors.New("error2")- 这是一个并行赋值语句,同时定义了变量
a和新的变量err。 a被赋值为字符串"ssss"。err被赋值为errors.New("error2")。
- 这是一个并行赋值语句,同时定义了变量
为什么输出是 error2 而不是 error?
- 在
defer延迟执行函数中,输出的err变量实际上是在msg()函数返回时执行的结果。 - 在
msg()函数中,虽然先定义了err := errors.New("error"),但是后来在并行赋值语句a, err := "ssss", errors.New("error2")中又定义了一个新的err变量。 - 在
defer延迟执行函数内部,闭包捕获的是msg()函数返回时的变量状态。由于在执行msg()函数过程中,后续的并行赋值语句err := errors.New("error2")改变了err变量的值,所以在defer函数内部输出的是最近的err变量,即errors.New("error2")。
总结:
- 输出的
err变量是在defer延迟执行函数内部捕获的msg()函数返回时的值。 - 并行赋值语句
a, err := "ssss", errors.New("error2")中重新定义了err变量,因此在defer函数中捕获的是最近的err变量,即errors.New("error2")。
另外一个容易出错的作用域的问题:
func msg() (result string) {
err := errors.New("error")
defer func() {
fmt.Printf("defer, err:%v", err) // 这里为啥是error2,而不是error?
}()
a, err := "ssss2", errors.New("error2") // 这个为啥不会报错?
fmt.Println(a)
{
a, err := "ssss3", errors.New("error3")
fmt.Println(a, err)
}
return
}
如果是这样的话,defer的时候输出是error2的
ssss2
ssss3 error3
defer, err:error2
PASS
这是因为作用域不同的问题

浙公网安备 33010602011771号