Go语言中defer和return解析
Posted 刘贤松handler
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言中defer和return解析相关的知识,希望对你有一定的参考价值。
1、return非原子性
Golang语言中函数的return不是原子操作,在底层是分为两步来执行
第一步:返回值 赋值
第二步:真正的RET返回
首先明确return执行前都做了哪些事情。
return是非原子性的,需要两步,执行前首先要得到返回值(为返回值赋值),return将返回值返回调用处。
函数中如果存在 defer,那么 执行顺序时机是在第一步和第二步之间
第一步:返回值 赋值
// defer
第二步:真正的RET返回
2、defer、return、返回值之间的关系
例子1:无名返回值(即函数返回值为没有命名的返回值)
package main
import (
"fmt"
)
func main()
fmt.Println("return:", Demo()) // 打印结果为 return: 0
func Demo() int
var i int
defer func()
i++
fmt.Println("defer2:", i) // 打印结果为 defer: 2
()
defer func()
i++
fmt.Println("defer1:", i) // 打印结果为 defer: 1
()
return i
输出结果:
defer2 1
defer1 2
return: 0
例子2:有名返回值(函数返回值为已经命名的返回值)
package main
import (
"fmt"
)
func main()
fmt.Println("return:", Demo2()) // 打印结果为 return: 2
func Demo2() (i int)
defer func()
i++
fmt.Println("defer2:", i) // 打印结果为 defer: 2
()
defer func()
i++
fmt.Println("defer1:", i) // 打印结果为 defer: 1
()
return i // 或者直接 return 效果相同
输出结果:
defer2 1
defer1 2
return: 2
从上面的测试用例可以看出,返回值,defer,return之间的执行顺序是:
先为返回值赋值,然后执行defer,然后return到函数调用处。
测试用例1 :
实际上return 执行了两步操作。
因为返回值没有命名,所以return 之前
首先默认创建了一个临时零值变量(假设为s)作为返回值
然后将i赋值给s,此时s的值是0。后续的操作是针对i进行的,
所以不会影响s, 此后因为s不会更新,
所以return s 不会改变
相当于:
var i int
s := i
return s
测试用例2:
因为返回值已经提前定义了,不会产生临时零值变量,
返回值就是提前定义的变量,后续所有的操作也都是基于已经定义的变量,
任何对于返回值变量的修改都会影响到返回值本身。
就相当于s就是命名的变量i, 后续所有的操作都是基于
命名变量i(s),返回值也是i, 所以每一次defer操作,
都会更新返回值i。
加强分析举例:
package main
import (
"fmt"
)
// Go语言中函数的return不是原子操作,在底层是分为两步来执行
// 第一步:返回值赋值
// defer
// 第二步:真正的RET返回
// 函数中如果存在defer,那么defer执行的时机是在第一步和第二步之间
func f1() int
x:=5
defer func()
x++ // 修改的是x不是返回值
()
return x // 1. 返回值赋值 2.defer 3.真正的ret指令
func f2()(x int)
defer func()
x++
()
return 5 // 返回值=x
func f3() (y int)
x:=5
defer func()
x++ // 修改的是x
()
return x // 1. 返回值 = y = x = 5 2. defer修改的是x 3. 真正的返回
func f4()(x int)
defer func (x int)
x++ // 改变的是函数中x的副本
(x)
return 5 // 返回值 = x = 5
func f5()(x int)
defer func (x int) int
x++
return x
(x)
return 5 // 1.x = 5 2. defer x = 6 3 真正的返回
func f6()(x int)
defer func (x *int) *int
(*x)++
return x
(&x)
return 5 // 1. x = 5 // 2.defer x =6 3. ret返回
func main()
fmt.Println(f1()) // 5
fmt.Println(f2()) // 6
fmt.Println(f3()) // 5
fmt.Println(f4()) // 5
fmt.Println(f5()) // 5
fmt.Println(f6()) // 6
以上是关于Go语言中defer和return解析的主要内容,如果未能解决你的问题,请参考以下文章