先来看例子:
例子1:
package main
import "fmt"
func refertest() int {
var i int
fmt.Printf("在没有调用defer之前。i的值为:%d,i的地址为:%p", i, &i)
fmt.Println()
defer func() {
i++
fmt.Printf("第一个defer。i的值为:%d,i的地址为:%p", i, &i)
fmt.Println()
}()
defer func() {
i++
fmt.Printf("第二个defer。i的值为:%d,i的地址为:%p", i, &i)
fmt.Println()
}()
return i
}
func main() {
fmt.Println("main", refertest())
}
从这个例子看到i变量的地址一样。defer func修改的i跟返回i变量都是同一个变量,为什么return i 是0?
例子2:我们取消defer,再来测试一下。
package main
import "fmt"
func refertest() int {
var i int
fmt.Printf("在没有调用defer之前。i的值为:%d,i的地址为:%p", i, &i)
fmt.Println()
//取消defer
func() {
i++
fmt.Printf("第一个defer。i的值为:%d,i的地址为:%p", i, &i)
fmt.Println()
}()
//取消defer
func() {
i++
fmt.Printf("第二个defer。i的值为:%d,i的地址为:%p", i, &i)
fmt.Println()
}()
return i
}
func main() {
fmt.Println("main", refertest())
}
终于看到i的返回是2了,导致上一个例子返回为0,主要原因是defer这个延迟执行导致。
例子3,我们对程序进行修改一下
package main
import "fmt"
//在函数返回中加上(i int).
func refertest() (i int) {
//注释掉函数中对i变量的声明。
//var i int
fmt.Printf("在没有调用defer之前。i的值为:%d,i的地址为:%p", i, &i)
fmt.Println()
defer func() {
i++
fmt.Printf("第一个defer。i的值为:%d,i的地址为:%p", i, &i)
fmt.Println()
}()
defer func() {
i++
fmt.Printf("第二个defer。i的值为:%d,i的地址为:%p", i, &i)
fmt.Println()
}()
return i
}
func main() {
fmt.Println("main", refertest())
}
例子1:返回i是0,我们得到一个结论defer执行顺序是:return负责将结果写入返回值中->接着defer开始执行一些收尾工作->最后函数携带当前返回值return退出。return的语句已经事先将返回值i给定义下来了,就是0。然后再等待defer执行对i++的修改。最后操作返回也不会影响return之前的赋值。
例子3:由于返回值提前声明了,所以在return的时候决定的返回值还是0,但是后面两个defer执行后进行了两次++,将i的值变为2,待defer执行完后,函数将i值进行了返回。
例子4,我们修改程序,把return i修改成return &i,返回i变量地址,不返回值。这个时候是可以返回2.
package main
import "fmt"
// func refertest() (i int)
func refertest() *int {
var i int
fmt.Printf("在没有调用defer之前。i的值为:%d,i的地址为:%p", i, &i)
fmt.Println()
defer func() {
i++
fmt.Printf("第一个defer。i的值为:%d,i的地址为:%p", i, &i)
fmt.Println()
}()
defer func() {
i++
fmt.Printf("第二个defer。i的值为:%d,i的地址为:%p", i, &i)
fmt.Println()
}()
return &i
}
func main() {
//由于返回是指针变量。这里必须使用*来接收。
fmt.Println("main", *refertest())
}