美文网首页
轻松搞定defer和return

轻松搞定defer和return

作者: 皇甫LG | 来源:发表于2020-05-08 21:25 被阅读0次

    怎么才能深刻理解defer和return之间关系呢?细读本文后将对你有很大帮助。

    一、理解基本概念

    1. go函数中return不是原子操作,在编译器中分解为两个部分:返回值赋值和return, 而defer则刚好被插入到末尾的return之前执行,因此可以在defer函数中修改返回值。

    2. 多个defer的执行顺序为LIFO(后进先出)

    3. defer、return、返回值三者的执行逻辑应该是:return最先执行,return负责将结果写入返回值中;接着defer开始执行一些收尾工作;最后函数携带当前返回值退出。

    然后尝试解答以下示例,本文末尾会有答案和解析说明,手动写下答案后,对比本文末尾答案或者直接运行查看结果是否和手写的答案一样呢?

    二、开始做题

    • 示例1
    func increaseA() int {
        var i int
        defer func() {
            i++
        }()
        return i
    }
    
    func increaseB() (r int) {
        defer func() {
            r++
        }()
        return r
    }
    
    func main() {
        fmt.Println(increaseA())
        fmt.Println(increaseB())
    }
    
    • 示例2
    func f1() (r int) {
        defer func() {
            r++
        }()
        return 0
    }
    
    func f2() (r int) {
        t := 5
        defer func() {
            t = t + 5
        }()
        return t
    }
    
    func f3() (r int) {
        defer func(r int) {
            r = r + 5
        }(r)
        return 1
    }
    
    func f4() (r int) {
        t := 5
        defer func() {
            r = t + 5
        }()
        return t
    }
    
    
    • 示例3
    var a bool = true
    func main() {
        defer func(){
            fmt.Println("1")
        }()
        if a == true {
            fmt.Println("2")
            return
        }
        defer func(){
            fmt.Println("3")
        }()
    }
    
    • 示例4
    func calc(index string, a, b int) int {
        ret := a + b
        fmt.Println(index, a, b, ret)
        return ret
    }
    
    func main() {
        a := 1
        b := 2
        defer calc("1", a, calc("10", a, b)) 
        a = 0
        defer calc("2", a, calc("20", a, b))
        b = 1 
    }
    

    建议手动写下答案,如果有模糊的地方,然后在返回基础概念模块,在认真读一下。

    三、答案及解析

    • 示例1
    输出结果: 0  1
    分析说明:好好理解一下概念3。以匿名返回值方法(increaseA())举例
    发生return时,将赋值给返回值(可以理解为go自动创建了一个返回值retValue,相当于执行了retValue=value),此时defer修改该的是value而不是retValue。
    
    而在命名返回值函数中,由于返回值在方法定义时已经被定义,所以不会在创建retValue了,defer对value的修改也会被直接返回。
    
    • 示例2
    输出结果: 1, 5, 1, 10
    分析说明: 概念3, f3() 变量作用域问题。
    
    • 示例3
    输出结果: 2  1
    
    分析说明: 关键字后面的函数或者方法想要执行必须先注册,return 之后的 defer 是不能注册的, 也就不能执行后面的函数或方法。
    
    • 示例4
    输出结果: 
    10 1 2 3
    20 0 2 2
    2 0 2 2
    1 1 3 4
    
    分析说明: 不管代码顺序如何,defer calc func中参数b必须先计算,故会在运行到第三行时,执行calc("10",a,b)输出:10 1 2 3得到值3,将cal("1",1,3)存放到延后执执行函数队列中。
    
    执行到第五行时,现行计算calc("20", a, b)即calc("20", 0, 2)输出:20 0 2 2得到值2,将cal("2",0,2)存放到延后执行函数队列中。
    
    执行到末尾行,按队列先进后出原则依次执行:cal("2",0,2)、cal("1",1,3) ,依次输出:2 0 2 2、1 1 3 4 。
    

    相关文章

      网友评论

          本文标题:轻松搞定defer和return

          本文链接:https://www.haomeiwen.com/subject/knsqnhtx.html