defer特性:

  1. 关键字 defer 用于注册延迟调用。
  2. 这些调用直到 return 前才被执。因此,可以用来做资源清理。
  3. 多个defer语句,按先进后出的方式执行。
  4. defer语句中的变量,在defer声明时就决定了。

defer用途:

  1. 关闭文件句柄
  2. 锁资源释放
  3. 数据库连接释放
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


欢迎关注公众号:程序员开发者社区

Go defer 使用_开发者社区


关注我们,了解更多



参考资料