zoukankan      html  css  js  c++  java
  • golang defer那些坑

    defer以下几个特性,使用时需要关注下。

    • 即时的参数传递
    • 调用os.Exit()时defer不会被执行
    • defer与return的先后顺序

    1.即时的参数传递

    定义defer时传入的参数,是作为拷贝传递的。
    也就是说,如果原来的变量值发生变化,不会影响传给defer的参数。

    例子如下:

    package main
    
    import (
            "fmt"
    )
    
    
    func main(){
    
            test()
    
    }
    
    func test() {
            a := 0
    
            defer func (i int) {
                    fmt.Println("in defer i:", i)
            }(a)
    
            a += 1
            fmt.Println("a:", a)
    }
    

    输出结果:

    a: 1
    in defer i: 0
    

    可以看到,即使变量a发生变化,延迟执行时变量的值仍然是0,与定义defer时传入的值一样。

    2.调用os.Exit()时defer不会被执行

    当发生panic时,defer会被执行,但是当调用os.Exit()方法退出程序时,defer并不会被执行。

    package main
    
    import (
            "fmt"
            "os"
    )
    
    
    func main(){
            fmt.Println("main start")
            test()
    }
    
    func test() () {
            defer func () {
                    fmt.Println("in defer ... ")
            }()
    
            os.Exit(0)
    }
    

    输出结果:

    main start
    

    defer定义的内容没有输出。

    3.defer 与 return先后顺序

    先来看两个例子:一个是返回匿名变量,一个是返回命名变量。

    3.1 返回匿名变量

    package main
    
    import (
            "fmt"
    )
    
    
    func main(){
            i := test()
            fmt.Println("main i:", i)
    }
    
    func test() int {
            a := 0
            defer func () {
                    a = 2
            }()
    
            a = 1
            return a
    }
    

    定义a为0, 接着修改为1,最后在defer中将a修改为2。

    在main中返回的值仍然是1.

    输出结果:

    main i: 1
    

    3.2 返回命名变量

    package main
    
    import (
            "fmt"
    )
    
    
    func main(){
            i := test()
            fmt.Println("main i:", i)
    }
    
    func test() (a int) {
            defer func () {
                    a = 2
            }()
    
            a = 1
            return a
    }
    

    defer中修改a为2,能够返回给调用方。

    输出结果:

    main i: 2
    

    实际上,defer 函数的执行既不是在 return 之后也不是在 return 之前,而是 return 语句包含了对 defer 函数的调用,即 return 会被翻译成如下几条伪指令:

    保存返回值到栈上(如果是匿名变量,需要定义变量并赋值)
    调用defer函数(如果有defer函数,则调用并执行)
    调整函数栈
    retq指令返回(如果是匿名变量,直接返回新定义的变量,如果是命名变量,直接返回命名变量)
    

    命名变量返回时,不会创建新的变量,所以defer的修改会返回去。
    而匿名变量,会创建新的变量,defer中的修改,还是修改原来的变量,所以修改不能返回去。

    4.参考

    Defer, Panic, and Recover

    https://juejin.im/post/5b9b4acde51d450e5071d51f

    https://my.oschina.net/henrylee2cn/blog/505535

  • 相关阅读:
    vue (v-if show 问题)
    vue 打包成 apk 文件(修改路径)
    移动端meta几个值的设置以及含义
    vue-cli 搭建
    call() 和 apply() 的作用和区别
    关于闭包的理解
    js的style和getArribute("属性名")
    vue的生命周期
    css3新特性选择器(补充)
    css3的新特性选择器-------属性选择器
  • 原文地址:https://www.cnblogs.com/lanyangsh/p/11074304.html
Copyright © 2011-2022 走看看