golang中defer的详解

来源:互联网 发布:史上最恶搞游戏之网络 编辑:程序博客网 时间:2024/06/01 08:18

    Godefer语句用来调度一个函数调用(被延期的函数),使其在执行defer的函数即将返回之前才被运行,被延期执行的函数,它的参数(包括接受者)实在defer执行的时候被求值的,而不是在调用执行的时候。也就是说被延期执行的函数的参数是按正常顺序被求值的。

    defer会按逆序执行

    deferGo语言提供的关键字,常用来释放资源,会在函数返回之前进行调用。如果有多个defer表达式,调用顺序类似于栈,越后面的defer表达式越先被调用。defer 函数调用的执行时机是外层函数设置返回值之后并且在即将返回之前

 

1

 

func main() {
         for i:=;i<5;i++{
              defer fmt.Printf("%d",i)
              fmt.Println("bbbbb")
         }
         fmt.Println("aaaaa")
}

 

执行结果:

bbbbb

bbbbb

bbbbb

bbbbb

bbbbb

aaaaa

43210

 

2

func trace(s stringstring {
       fmt.Println("entering:",s)
       return s
}

func un(s string) {
       fmt.Println("leaving:",s)
}

func a() {
       defer un(trace("a"))
       fmt.Println("in a")
}

func b() {
       defer un(trace("b"))
       fmt.Println("in b")
       a()
}

 

func main() {
       b()
}

 

 

执行结果如下:

entering: b

in b

entering: a

in a

leaving: a

leaving: b

 

 

 例3

func f1() (result int) {
       defer func() {
              result++
       }()
       return 0
}

func f2() (r int) {
       t := 5
       defer func() {
              t = t+5
       }()
       return t
}


func f3() (t int) {
       t = 5
       defer func() {
              t = t+5
       }()
       return t
}


func f4() (r int) {
       defer func(r int) {
              r = r + 5
       }(r)
       return 1
}

 

要使用defer不踩坑,最重要的一点就是明白,return xxx不是一条原子指令

 

函数返回的过程是这样子的:先给返回值赋值,然后调用defer表达式,最后才是返回到调用函数中。

defer表达式可能会在设置函数返回值之后,在返回到调用函数之前,修改返回值,使最终的函数返回值与你想象的不一致。

 

可以将return xxx改成

返回值=xxx

调用defer函数

空的return

 

 

 

3可以改写成这样

func f11() (result int) {
       result = 0   //先给返回值赋值
       func(){               //再执行defer 函数
              result++
       }()
       return                //最后返回
}

func f22() (r int) {
       t := 5
       r = t //赋值指令
       func(){   //defer 函数被插入到赋值与返回之间执行,这个例子中返回值r没有被修改
              t = t+5
       }
       return   //返回
}

func f33() (t int) {
       t = 5    //赋值指令
       func(){
              t = t+5  //然后执行defer函数,t值被修改
       }
       return
}

func f44() (r int) {
       r = 1    //给返回值赋值
       func(r int){   //这里的r传值进去的,是原来rcopy,不会改变要返回的那个r
              r = r+5
       }(r)
       return
}

 

参考:《Effective Go》、《深入解析go内核实现》

原创粉丝点击