defer

defer #

Go 处理 defer 和 return 的顺序为:

  1. 计算 return 语句的返回值
  2. 赋值给匿名 / 有名返回值
  3. 执行 defer
  4. return 退出函数

Defer 的用途跟其他语言的 ensurefinally 类似。

当 defer 释放锁遇到尾递归,会产生死锁 #

如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。

计算 return 语句的值,赋值给匿名/有名返回值 -> defer -> return 退出函数

var mut = sync.Mutex{}
func tailRec(i int) int {
    mut.Lock()          // 加锁
    defer mut.Unlock()  // defer 释放锁
    if i == 10 {
        return i
    }
    i++
    return tailRec(i)   // return 尾递归
}

以上代码执行会发生死锁,原因是 return 语句后的命令先执行,赋值给匿名返回值后,再调用 defer, 因此尾递归中 tailRec 的加锁会在 defer 释放锁之前进行,形成死锁。

参考:

返回值求值 #

// 匿名返回值
func test_unnamed()(int) {
    var i int
    defer func() {
        i++
        fmt.Println("defer a:", i)
    }()
    defer func() {
        i++
        fmt.Println("defer b :", i)
    }()
    return i // 0
}

// 具名返回值
func test_named()(i int) {
    defer func() {
        i++
        fmt.Println("defer c:", i)
    }()
    defer func() {
        i++
        fmt.Println("defer d :", i)
    }()
    return i // 2
}

本文访问量

本站总访问量

本站总访客数