G

Golang Defer 理解

Yuming 代码 2022-01-13

结论

  1. 多个defer的执行顺序为先进后出
  2. 匿名返回值是在return执行时被声明,有名返回值则是在函数声明的同时被声明,因此在defer语句中只能访问有名返回值,而不能直接访问匿名返回值
  3. return其实应该包含前后两个步骤:第一步是给返回值赋值(若为有名返回值则直接赋值,若为匿名返回值则先声明再赋值);第二步是调用RET返回指令并传入返回值,而RET则会检查defer是否存在,若存在就先逆序插播defer语句,最后RET携带返回值退出函数
  4. 延迟函数的参数在 defer 语句出现时就已经确定下来了(defer声明时会先计算确定参数的值,defer推迟执行的仅是其函数体)

解释

结论1
package main

func main() {
    for i := 0; i < 4; i++ {
        defer fmt.Print(i)
    }

    // Output:
    // 3
    // 2
    // 1
    // 0
}
结论2和结论3
package main

import (
    "fmt"
)

func main() {
    fmt.Println(a())

    // Output:
    // 1
    // 2
}

// 无名返回值
func a() int {
    defer func() { i++ }()
    return 1
}

// 有名返回值
func a() (i int) {
    defer func() { i++ }()
    return 1
}
结论4
package main

import (
    "fmt"
)

func main() {
    a()
    b()

    // Output:
    // 0
    // enter: b
    // in b
    // leave: b
}

func a() {
    i := 0
    defer fmt.Println(i) // 调用时i已经确定为0
    i++
    return
}

func trace(s string) s {
    fmt.Println("enter: ", s)
    return s
}

func un(s) {
    fmt.Println("leave: ", s)
}

func b() {
    defer un(trace("b")) // defer声明时会先计算确定参数的值,即执行了trace(),defer推迟执行的仅是其函数体un()
    fmt.Println("in b")
}

参考

  1. 《Go语言设计与实现》
  2. Golang中defer、return、返回值之间执行顺序的坑
  3. 理解Golang中defer的使用
PREV
Casbin 理解
NEXT
SQL提交规范

评论(0)

发布评论