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
}

 

分析:

  1. 第一部分:err := errors.New("error")

    • 这行代码定义了一个名为 err 的变量,并赋值为 errors.New("error")
  2. 第二部分:defer func() { fmt.Println(err) }()

    • 这里使用了 defer 延迟执行函数,它捕获了外部函数的 err 变量。
    • 注意,这里的 defer 函数中使用的 err 是一个闭包,它会在 msg() 函数返回时执行。在执行时,它捕获的是 msg() 函数返回时的 err 变量的值。
  3. 第三部分: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

这是因为作用域不同的问题

posted @ 2024-07-08 13:39  若-飞  阅读(1)  评论(0编辑  收藏  举报