轻松搞定defer和return

2020-05-08  本文已影响0人  皇甫LG

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

一、理解基本概念

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

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

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

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

二、开始做题

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())
}
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
}

var a bool = true
func main() {
    defer func(){
        fmt.Println("1")
    }()
    if a == true {
        fmt.Println("2")
        return
    }
    defer func(){
        fmt.Println("3")
    }()
}
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 
}

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

三、答案及解析

输出结果: 0  1
分析说明:好好理解一下概念3。以匿名返回值方法(increaseA())举例
发生return时,将赋值给返回值(可以理解为go自动创建了一个返回值retValue,相当于执行了retValue=value),此时defer修改该的是value而不是retValue。

而在命名返回值函数中,由于返回值在方法定义时已经被定义,所以不会在创建retValue了,defer对value的修改也会被直接返回。
输出结果: 1, 5, 1, 10
分析说明: 概念3, f3() 变量作用域问题。
输出结果: 2  1

分析说明: 关键字后面的函数或者方法想要执行必须先注册,return 之后的 defer 是不能注册的, 也就不能执行后面的函数或方法。
输出结果: 
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 。
上一篇 下一篇

猜你喜欢

热点阅读