【Go 基础】defer 关键字

defer关键字

什么是defer?为什么需要defer?如何使用deferdefer的执行顺序是什么?

  • 什么是defer?

deferGo 语言的一种用于注册延迟调用的机制,使得函数或语句可以在当前函数执行完毕后执行。

  • 为什么需要defer?

Go语言提供的语法糖,减少资源泄露的发生。

  • 如何使用defer?

在创建资源语句的附近,使用defer语句释放资源。

  • defer的执行顺序是什么?

出栈顺序(先进后出),它的执行顺序与声明顺序相反。

defer 的常用场景:

  • defer语句经常被用于处理成对的操作,如打开、关闭、连接、断开连接、加锁、释放锁。
  • 通过defer机制,不论函数逻辑多复杂,都能保证在任何执行路径下,资源被释放。
  • 释放资源的defer应该直接跟在请求资源的语句后。

defer关键字的使用,写出下面代码的输出内容。

package main

import (
    "fmt"
)

func main() {
    deferCall()
}
func deferCall() {
    defer func() { fmt.Println("打印前") }()
    defer func() { fmt.Println("打印中") }()
    defer func() { fmt.Println("打印后") }()
    panic("触发异常")
}

结果:

打印后
打印中
打印前
panic: 触发异常

解析:

defer 关键字的实现跟go关键字很类似,不同的是它调用的是 runtime.deferproc 而不 是 runtime.newproc

defer 出现的地方,插入了指令 call runtime.deferproc ,然后在函数返回之前的地 方,插入指令 call runtime.deferreturn

goroutine的控制结构中,有一张表记录 defer ,调用 runtime.deferproc 时会将需要 defer的表达式记录在表中,而在调用 runtime.deferreturn 的时候,则会依次从defer表 中出栈(先进后出)并执行。

因此,题目最后输出顺序应该是 defer 定义顺序的倒序。 panic 错误并不能终止 defer 的执行。

拓展:

在函数中,开发者经常需要创建资源(比如:数据库连接、文件句柄、锁等) ,为了在函数执行完毕后,及时的释放资源,Go 的设计者提供 defer(延时机制)。

go 执行到一个 defer 时,不会立即执行 defer 后的语句,而是将 defer 后的语句压入到一个栈中,然后继续执行函数下一个语句。当函数执行完毕后,在从 defer 栈中,依次从栈顶(先入后出)取出语句执行。

defer 将语句放入到栈时,也会将相关的值拷贝同时入栈。值拷贝示例

package main

import (
    "fmt"
)

func sum(n1 int, n2 int) int {

    // 当执行到defer时,暂时不执行,会将defer后面的语句压入到独立的栈(defer栈)
    // 当函数执行完毕后,再从defer栈,按照先入后出的方式出栈,执行
    defer fmt.Println("ok1 n1=", n1) // defer 3. ok1 n1 = 10
    defer fmt.Println("ok2 n2=", n2) // defer 2. ok2 n2= 20
    //增加一句话
    n1++                         // n1 = 11
    n2++                         // n2 = 21
    res := n1 + n2               // res = 32
    fmt.Println("ok3 res=", res) // 1. ok3 res= 32
    return res
}

func main() {
    res := sum(10, 20)
    fmt.Println("res=", res) // 4. res= 32
} 

案例二:defer关键字的使用,写出下面代码的输出内容。

package main

import "fmt"

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
}

结果:

10 1 2 3
20 0 2 2
2 0 2 2
1 1 3 4

解析:defer 在定义的时候会计算好调用函数的参数,所以会优先输出 10 、 20 两个参 数。然后根据定义的顺序倒序执行。

相关推荐

微信扫一扫,分享到朋友圈

【Go 基础】defer 关键字
返回顶部

显示

忘记密码?

显示

显示

获取验证码

Close