示例一 defer的固定传参
代码语言:javascript复制package main
import "fmt"
func main() {
fmt.Println("主函数输出:", test())
}
func test() int {
res := 1000
defer fmt.Println("defer输出:", res)
res = 1000
return res
}
以上输出为:
原因是:defer 函数的参数在定义的时候就以及确定了(形参拷贝),所以后面就算修改了值也不会发生变化
示例二 defer函数确定
代码语言:javascript复制package main
import "fmt"
func main() {
fmt.Println("主函数输出:", test())
}
func test() int {
res := 1000
defer func() {
fmt.Println("defer输出:", res)
}()
res = 1000
return res
}
以上输出为:
原因是 defer只确定了一个匿名函数地址,匿名函数进行第二次的调用,在匿名函数确定好的时候,确定了res的地址,在执行匿名函数之后才开始获取res值然后进行形参传递输出,所以输出2000
示例三 defer 固定地址参数
代码语言:javascript复制package main
import "fmt"
func main() {
fmt.Println("主函数输出:")
deferFunction()
}
func deferFunction() {
var arr = []int{1, 2, 3}
defer fmt.Println("deferFunction:", arr)
arr[0] = 6
return
}
输出:
在defer时,确定了arr的地址(数组是地址形式,直接传递地址),所以在打印时,可以打印到更改的数据
示例四 defer return执行步骤
代码语言:javascript复制package main
import "fmt"
func main() {
fmt.Println("主函数输出:", deferFunction())
}
func deferFunction() (result int) {
result = 1
defer func() {
result = 2
}()
return
}
输出:
原因是:
函数调用的执行步骤为: 调用函数->设定返回值result->赋值result=1->准备return,return的值为resulr->执行defer赋值为2->return执行完毕,正式返回
所以输出2
示例五
代码语言:javascript复制package main
import "fmt"
func main() {
fmt.Println("主函数输出:", deferFunction())
}
func deferFunction() (result int) {
i := 1
defer func() {
result = 2
}()
return i
}
输出:
原因是:
return的调用并非原子性的,分为2个步骤:1 确定返回值,2正式返回
在确定返回值之后,会去执行defer方法,如果defer将返回值变更,则返回时数据也会变更.
在此示例中,return将i赋值给了result,这个时候result=1,同时result又更改成了2,所以为2
总结
规则一:延迟函数的参数在声明时就确定下来了
defer函数在声明时就已经确定好了参数,并且形参做了一次值拷贝,成为了一个新值
这个规则对于指针类型也同样适用,相当于拷贝了一份指针,但是指针指向的值确实实实在在变了的
规则二:延迟函数执行按后进先出顺序执行,即先出现的defer最后执行
defer函数在声明后类似于入栈操作,调用时候类似于出栈操作,所以是后进先出执行
规则三:函数返回过程非原子操作
return时非原子操作的,return操作的是将返回值存入栈中等待操作,
然后执行返回跳转
但是在执行返回跳转操作时,还需要执行defer函数,所以在defer函数中可以操作这个返回值
但是在特殊情况下,defer函数无法操作返回值
特殊情况一:函数有匿名返回值,直接返回字面量
代码语言:javascript复制func test() int {
i := 0
defer func() {
i
}()
return 1
}
该函数直接将1写入返回值,所以defer无法操作返回值
特殊情况二:函数有匿名返回值,返回变量
代码语言:javascript复制func test() int {
i := 0
defer func() {
i
fmt.Println(i)
}()
return i
}
该情况下,defer可以引用到i的变量值,进行一次值拷贝,所以defer操作的是拷贝后的i值,不会发生变化(如果返回变量类型为指针类型,则会发生变化)
本文为仙士可原创文章,转载无需和我联系,但请注明来自仙士可博客www.php20.cn