博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Go里的defer很有用,尤其在很多执行模块化操作时,初始化时给各个需要执行的模块传入参数,但是这些参数有些事在模块执行过程中才赋值的。

这时候有了defer就不会把代码写的很凌乱。

 

 

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

    defer会按逆序执行

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

 

例1:

 

func main() {
         for i:=0 ;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 string) string {
       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传值进去的,是原来r的copy,不会改变要返回的那个r值
              r = r+5
       }(r)
       return
}

 

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