关于延时调用函数(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 }
匿名返回值:
package main import "fmt" func a() int { var i int defer func() { i ++ fmt.Println(i) }() defer func() { i ++ fmt.Println(i) }() return i } func main() { fmt.Println("a return: ",a()) }
运行打印输出结果:
1 2 a return: 0