Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Go defer return

详解Go中defer与return的执行顺序

作者:nil

Go defer中改变return的值会生效吗,这就设计到了GO语言中defer与return哪个先执行的问题了,下面小编就通过简单的示例来和大家讲讲吧

示例

直接上代码

func test() int {
   result = 123
   defer func() {
      result = 456
   }()
   return result
}
func main() {
   fmt.Println(test())
}

结果

123

修改之后的代码

func test() (result int) {
   result = 123
   defer func() {
      result = 456
   }()
   return result
}
func main() {
   fmt.Println(test())
}

结果

456

再看下面这个例子

func test() (result int) {
   result = 123
   defer func() {
      fmt.Println("aaa")
      result = 456
   }()
   return func() int {
      fmt.Println("bbb")
      return result
   }()
}
func main() {
   fmt.Println(test())
}

结果

bbb
aaa
456

defer与return哪个先执行

这个问题主要是defer 与return哪个先执行。很容易理解如果一个函数中有多个defer,它是栈的形式保存的,执行的时候先从栈顶执行,即后面定义的defer会先被执行,并且defer是在return执行之后才执行的。

因为defer是在return 执行之后才执行的,所以第三个例子中先打印bbb后打印aaa很好理解。

第二个例子和第三个例子test函数返回456也好理解,因为defer可以改变返回值中定义的变量。虽然return已经返回了,defer还是可以改变它。

第一个例子,defer改变的不是返回值中定义的变量,而是局部变量,这个时候return已经执行了,defer改变局部变量没有用。在defer中改变局部变量的值没有效果。第一个例子return result是值拷贝,即将result的值拷贝一份并返回,因此defer改变result并不会影响返回值。

第二、第三例子中return返回的result不是值拷贝,因为result是在返回值中定义的变量,所以return返回的直接是那个变量,这个时候没有值拷贝

再看看下面这个例子

func test() *int {
   result := 123
   defer func() {
      result = 456
   }()
   return &result
}
func main() {
   fmt.Println(*test())
}

结果

456

这个时候defer改变局部变量result又生效了,这是为什么?是因为return 返回的是局部变量的地址,而不是局部变量的只拷贝。因此在defer中修改局部遍历会影响返回结果。

总结

上面描述可能有点绕,需要亲自实验一下,仔细理解才能真正搞懂。下面总结一下我的理解:

return 返回有2种方式:

值拷贝:将局部变量的值拷贝到返回值上。return 直接返回局部变量的值(不是局部变量的引用)

非值拷贝:即return 返回值的时候没有发生值拷贝,有两种情况:

非值拷贝的情况下,defer修改返回值是生效的。

return 的执行其实用两步骤:1.先将return的结果赋值到返回值上;2.再将返回值赋值作为函数的结果赋值给调用者。

defer的执行是在return的两步骤中间执行的。所以return如果发生了值拷贝则defer不会改变返回结果;如果return没有发生值拷贝则defer会改变返回结果。

到此这篇关于详解Go中defer与return的执行顺序的文章就介绍到这了,更多相关Go defer return内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文