Post

defer

defer触发时机

  • 包裹着defer语句的函数返回时(先入栈的defer后执行)

    • 1
      2
      3
      4
      5
      6
      7
      8
      
       	// 输出结果:
        	// return前执行defer2
        	// return前执行defer1
         func f1() {
             defer fmt.Println("return前执行defer1")
             defer fmt.Println("return前执行defer2")
             return 
         }
      
  • 当前goroutine发生Panic时

    • 1
      2
      3
      4
      5
      6
      
      //输出结果:panic前  第一个defer在Panic发生时执行,第二个defer在Panic之后声明,不能执行到
         func f3() {
             defer fmt.Println("panic前")
             panic("panic中")
             defer fmt.Println("panic后")
         }
      

defer,return,返回值的执行顺序

  • 1. 先给返回值赋值

  • 2. 执行defer语句

  • 3. 包裹函数return返回

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    // 例1:匿名返回值
    // 可以看作:1、ret = r; 2、r = r *7; 3、return ret
    // 结果:6
    func f1() int { 
            var r int = 6
            defer func() {
                    r *= 7
            }()
            return r
    }
      
    // 例2:有名返回值
    // 可以看作:1、ret = 6; 2、ret = ret *7; 3、return ret
    // 结果:42
    func f2() (ret int) { //有名返回值
            defer func() {
                    ret *= 7
            }()
            return 6
    }
      
    // 例3:有名返回值
    // 可以看作:1、ret = 6; 2、无(因为defer定义时值传递); 3、return ret
    // 结果:6
    func f3() (ret int) { //有名返回值
        defer func(r int) {
            ret *= 7
        }(ret)
        return 6
    }
    

defer源码解析

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    
        type _defer struct {
                siz     int32 
                started bool
                sp      uintptr // 函数栈指针
                pc      uintptr // 程序计数器
                fn      *funcval // 函数地址
                _panic  *_panic // Panic是导致运行defer的Panic
            	link    *_defer // (链表)指向自身结构的指针,用于链接多个 defer
        }
    
  • 新建的延迟函数挂在当前goroutine的_defer的链表头部

参考

  • https://segmentfault.com/a/1190000020614493
This post is licensed under CC BY 4.0 by the author.