defer特性:
- 关键字 defer 用于注册延迟调用。
- 这些调用直到 return 前才被执。因此,可以用来做资源清理。
- 多个defer语句,按先进后出的方式执行。
- defer语句中的变量,在defer声明时就决定了。
defer用途:
- 关闭文件句柄
- 锁资源释放
- 数据库连接释放
package main import "fmt" func main() { var users [5]struct{} for i := range users { defer fmt.Println(i) } }
输出:4 3 2 1 0 ,defer 是先进后出
package defer_test import ( "fmt" "testing" ) func TestDefer1(t * testing.T) { var users [5]struct{} for i := range users { defer func() { fmt.Println(i) }() } }
输出结果:4 4 4 4 4 是否在想一个问题,输出结果不是 4 3 2 1 0 , 由于是闭包用到的变量 i 在执行的时候已经变成了4 , 所以输出全部是 4, 如何正常输出。4 3 2 1 0 ?不用闭包,换成函数即可。
func TestDefer2(t *testing.T) { var users [5]struct{} for i := range users { defer Print(i) } } func Print(i int) { fmt.Println(i) }
函数的输出结果是 :4 3 2 1 0
再看个结构体的例子
func (t *Users) GetName(){ fmt.Println(t.name) } func TestDefer3(t * testing.T){ list := []Users{{"乔峰"}, {"慕容复"},{"欧阳克"}} for _, t := range list { defer t.GetName() } }
发现没,输出的结果竟然是 欧阳克 欧阳克 欧阳克
不是欧阳克 慕容复 乔峰
如何要输出 :欧阳克 慕容复 乔峰
写个函数:
type Users struct { name string } func (t *Users) GetName(){ fmt.Println(t.name) } func GetName(t Users){ t.GetName() } func TestDefer4(t *testing.T) { list := []Users{{"乔峰"}, {"慕容复"},{"欧阳克"}} for _, t := range list { defer GetName(t) } }
函数输出结果:欧阳克 慕容复 乔峰
如果不想多写一个函数,输出 欧阳克 慕容复 乔峰
要怎么搞?复制一份即可
type Users struct { name string } func (t *Users) GetName() { fmt.Println(t.name) } func TestDefer5(t *testing.T) { list := []Users{{"乔峰"}, {"慕容复"}, {"欧阳克"}} for _, t := range list { t1 := t defer t1.GetName() } }
输出结果:欧阳克 慕容复 乔峰
defer 后面的语句在执行的时候,函数调用的参数会保存起来,复制一份,但是不执行。
多个 defer 注册,采用的是 FILO 先进后出的方式,哪怕函数发生错误, 这些调用依然会被执行。
func users(i int) { defer println("北丐") defer println("南帝") defer func() { println("西毒") println(10 / i) // 异常未被捕获,逐步往外传递,最终终止进程。 }() defer println("东邪") } func TestDefer6(t *testing.T) { users(0) println("武林高手排行榜,这里不会被输出") }
defer 与 return
在有命名返回值的函数中, 执行 return "风清扬"的时候实际上已经将 s 的值重新赋值为 风清扬
func Users2() (s string) { s = "乔峰" defer func() { fmt.Println("延迟执行后:" + s) }() return "清风扬" } func TestDefer7(t *testing.T) { Users2() // 输出:延迟执行后:清风扬 }
输出结果:
延迟执行后:清风扬 --- PASS: TestDefer7 (0.00s) PASS