Golang中的defer是使用频次比较高的,能创造出延迟生效特效的一种方式。bash
defer也有本身的矫情,须要注意的。 本文将从经过代码的方式来讲明defer的三点矫情。函数
1.defer的生效顺序 2.defer与return,函数返回值之间的顺序 3.defer定义和执行两个步骤,作的事情。ui
先说结论:defer的执行顺序是倒序执行(同入栈先进后出)spa
func main() {
defer func() {
fmt.Println("我后出来")
}()
defer func() {
fmt.Println("我先出来")
}()
}
复制代码
执行后打印出:指针
我先出来
我后出来
复制代码
先说结论:return最早执行->return负责将结果写入返回值中->接着defer开始执行一些收尾工做->最后函数携带当前返回值退出code
返回值的表达方式,咱们知道根据是否提早声明有两种方式:一种是func test() int 另外一种是 func test() (i int),因此两种状况都来讲说string
func test() intit
func main() {
fmt.Println("main:", test())
}
func test() int {
var i int
defer func() {
i++
fmt.Println("defer2的值:", i)
}()
defer func() {
i++
fmt.Println("defer1的值:", i)
}()
return i
}
复制代码
输出:io
defer1的值: 1
defer2的值: 2
main: 0
复制代码
详解:return的时候已经先将返回值给定义下来了,就是0,因为i是在函数内部声明因此即便在defer中进行了++操做,也不会影响return的时候作的决定。function
func test() (i int)
func main() {
fmt.Println("main:", test())
}
func test() (i int) {
defer func() {
i++
fmt.Println("defer2的值:", i)
}()
defer func() {
i++
fmt.Println("defer1的值:", i)
}()
return i
}
复制代码
输出:
defer1的值: 1
defer2的值: 2
main: 2
复制代码
详解:因为返回值提早声明了,因此在return的时候决定的返回值仍是0,可是后面两个defer执行后进行了两次++,将i的值变为2,待defer执行完后,函数将i值进行了返回。
先说结论:会先将defer后函数的参数部分的值(或者地址)给先下来【你能够理解为()里头的会先肯定】,后面函数执行完,才会执行defer后函数的{}中的逻辑
func test(i *int) int {
return *i
}
func main(){
var i = 1
// defer定义的时候test(&i)的值就已经定了,是1,后面就不会变了
defer fmt.Println("i1 =" , test(&i))
i++
// defer定义的时候test(&i)的值就已经定了,是2,后面就不会变了
defer fmt.Println("i2 =" , test(&i))
// defer定义的时候,i就已经肯定了是一个指针类型,地址上的值变了,这里跟着变
defer func(i *int) {
fmt.Println("i3 =" , *i)
}(&i)
// defer定义的时候i的值就已经定了,是2,后面就不会变了
defer func(i int) {
//defer 在定义的时候就定了
fmt.Println("i4 =" , i)
}(i)
defer func() {
// 地址,因此后续跟着变
var c = &i
fmt.Println("i5 =" , *c)
}()
// 执行了 i=11 后才调用,此时i值已经是11
defer func() {
fmt.Println("i6 =" , i)
}()
i = 11
}
复制代码