在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
关于延时调用函数(Deferred Function Calls) 延时调用函数基本语法如下: defer func_name(param-list) {} 当一个函数前有关键字 defer 时,那么这个函数执行会被推迟到包含这个 defer 语句的函数即将返回前才执行, 如下示例: package main import "fmt" func main() { defer fmt.Println("Fourth") fmt.Println("First") fmt.Println("Third") } 运行打印输出结果: First Third Fourth 需要注意的是,defer 调用的函数参数,在定义 defer 时就已经被确定了,如下示例: package main import "fmt" func main() { i := 1 defer fmt.Println("Deferred print:",i) i++ fmt.Println("Normal print:",i) } 运行打印输出结果: Normal print: 2 Deferred print: 1 从上面的结果中我们可以知道,在 defer fmt.Println("Deferred print:"i,) 调用时,i 的值就已经被确定了,因此相当 于 defer fmt.Println("Deferred print:",1) 需要强调的是,defer 调用的函数的参数值在 defer 定义时就已经被确定了,而 defer 函数内部所使用的变量的值需 要在运行时才确定。如下示例: package main import "fmt" func f1() (r1 int) { r := 1 defer func() { r ++ fmt.Println(r) }() r = 2 return } func main() { f1() } 运行打印输出结果: 3 上面的例子中,我们看到最终打印的内容是 "3" ,这是因为在 "r = 2" 之后才执行的 defer 函数,因此在这个函数内, r 的值是 2,自增后变成 3 defer 顺序 如果有多个 defer 调用,则调用的顺序是先进后出的顺序,类似于入栈出栈操作一样: package main import "fmt" func main() { defer fmt.Println(1) defer fmt.Println(2) defer fmt.Println(3) defer fmt.Println(4) } 运行打印输出结果: 4 3 2 1 defer 注意要点 defer 函数调用的执行时机是外层函数设置返回值之后,即将返回之前 如下示例: package main import "fmt" func f1() (r int) { defer func() { r ++ }() return 0 } func main() { fmt.Println(f1()) } 运行打印输出结果: 1 上面 fmt.Println(f1()) 打印的结果是 1,要弄明白这个问题,我们需要牢记两点: 1. defer 函数调用的执行时机是外层函数设置返回值之后,即将返回之前 2.return xxx 操作并不是原子 我们将上面的例子改写一下: func f1() (r int) { defer func() { r ++ }() r = 0 return } 当进行赋值操作 r = 0 之后,才执行调用 defer 函数,最后才执行返回语句 下面我们再看一个例子: package main import "fmt" func double(x int) int { return x + x } func triple(x int) (r int) { defer func() { r += x }() return double(x) } func main() { fmt.Println(triple(3)) } 上面的代码根据我们的讲解,可以改写成如下代码: func triple(x int) (r int) { r = double(x) defer func() { r += x }() return }
---------------------------------------------------------------------2019/03/04------------------------------------------------------ 转载地址:https://juejin.im/post/5b9b4acde51d450e5071d51f 参考文章:https://my.oschina.net/henrylee2cn/blog/505535 1:defer 在匿名返回值和有名返回值函数中的不同表现 先看下面两个方法执行的结果 func returnValues() int { var result int defer func() { result++ fmt.Println("defer") }() return result } func namedReturnValues() (result int) { defer func() { result++ fmt.Println("defer") }() return result } 上面的方法输出 0,下面的方法输出 1。上面的方法使用了匿名返回值,下面的方法使用了有名返回值,除此之外 逻辑都一样,但是为什么输出的结果的不一样呢? 1 多个 defer 的执行顺序为"先进后出" 2 所有函数在执行 return 返回指令之前,都会检查是否存在 defer 语句,如果存在将逆序调用 defer 语句执行完以后 在退出返回 3 有名返回值在函数声明的时候就已经被声明了,另外,return 不是一个原子操作,它包含前后两个步骤,第一步是: 给返回值赋值(如果是有名返回值则直接赋值,如果是匿名返回值则先声明再赋值);第二步是检查是否存在 defer 存在就 执行 defer, 最后结束函数运行 以匿名返回值为例,过程如下: 1. 因为匿名返回值并没有明确声明返回值,可以理解成 Go 自动创建声明了一个返回值 retValue ,然后将 result 赋值给 返回值 retValue 2.然后检查是否有 defer ,如果有则返回 3. 返回刚才创建的返回值 在这种情况下,defer 中的修改是对 result 执行的,而不是 retValue ,在有名返回值中,返回值已经在函数定义的时候就 已经被声明了,没有创建声明 retValue 的过程,直接赋值返回值 |
请发表评论