• Go基础知识----defer源码和多个defer执行顺序


    1. defer和defer的执行顺序

    1.1 代码示例
    func f4() {
    	defer func() {
    		fmt.Println("444")
    
    	}()
    
    	defer func() {
    		fmt.Println("555")
    	}()
    
    	println("dddddd")
    }
    func main() {
    	f4()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    输出:

    dddddd
    555
    444
    
    • 1
    • 2
    • 3

    如图可知,defer之间的输出顺序遵循栈的逻辑----先进后出,首先执行主程序代码,然后执行defer逻辑,在前面的defer最后执行,以此类推。

    2. defer和return的执行顺序

    2.1 当return的参数是无命名变量时

    ps 无命名变量:返回值列表只要返回类型没有变量名
    eg

    func f() int {
    	i := 5
    	defer func() {
    		i++
    	}()
    	return i
    }
    
    func main() {
    	println(f())
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    输出:

    5
    
    • 1

    分析:如图可知,当返回的是无名明变量时,i的值在defer中的改变将被忽略,因为return的是无名明变量,则return不是原子操作,则return执行逻辑如下
    1)var s int // 声明一个有命名变量
    2)s:=i
    3) 执行defer语句
    4) return s

    因为i在defer中的改变不会影响s的值,所以返回5

    2.2 当return的参数是有命名变量,且返回的是具体数字时

    eg:

    func f1() (result int) {
    	defer func() {
    		result++
    	}()
    	return 5
    }
    func main() {
     	println(f1())
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    输出:

    6
    
    • 1

    分析:内部执行逻辑
    1)result=5 // result为返回的有命名参数
    2) defer 语句 result变为6
    3)return result=6

    2.3 当return的参数是有命名变量,且返回的是自定义的局部变量时

    eg:

    func f2() (r int) {
    	t := 5
    	defer func() {
    		t = t + 5
    	}()
    	return t
    }
    func main() {
    	println(f2())
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    输出:

    5
    
    • 1

    分析:return执行逻辑如下:
    1)r=t (t变为5) // r为返回的有命名参数
    2) defer 语句 r变为10
    3)return r=5

    2.4 当return的参数是有命名变量,且返回的也是命名变量时,且defer是闭包时

    eg:

    
    func f3() (r int) {
    	defer func(r int) {
    		r = r + 5
    	}(r)
    	return r
    }
    func main() {
    	println(f3())
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    输出:

    0
    
    • 1

    分析:return执行逻辑如下:
    1)r=0 (r变为0) // r为返回的有命名参数
    2) defer 语句执行:

    defer func(r int) {  // 重新定义的r 跟外部的r不是一个地址
    		r = r + 5   
    	}(r)  // 外部传递的r为值传递
    
    上式等价于下式:
    
    defer func(a int) {   
    		a = a + 5   
    	}(r)   
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    由于r在参数传递过程中是值传递,所以其本身不会随闭包值得改变而改变(地址不同),则外边r为0
    3)return r=0

    2.5 当return的参数是有命名变量,且返回的也是命名变量时,且返回参数跟defer中是一个参数时。

    eg:

    package main
     
    import "fmt"
    func test1(x int) int { 
        defer func() { x = 9 }()
        x = 10 
        return x 
    }
    func main() {
        fmt.Println("Hello, World!",test1(100))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    分析:???,不应该是9吗,原因待查,希望知道大神指导下。
    输出:10

    3. defer源码

    待分析

  • 相关阅读:
    c++香甜的黄油(acwing)
    Laravel框架进阶:掌握队列系统,优化应用性能
    IEDA 自动生成类注释和方法注释
    四元数插值
    Vue3 引入Vanta.js使用
    C#多线程
    【前端】HTML入门 —— HTML的常见标签
    图斑自上而下,自左而右顺序编码,按照权属单位代码分组,每组从1开始编码
    深入Linux内核(进程篇)—进程切换之ARM体系架构 简单总结
    【Leetcode合集】13. 罗马数字转整数
  • 原文地址:https://blog.csdn.net/u013915286/article/details/126301281