1.首先明确return执行前都做了哪些事情。
return是非原子性的,需要两步,执行前首先要得到返回值(为返回值赋值),return将返回值返回调用处。
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。