Go语言之defer

defer关键字

defer和go一样都是Go语言提供的关键字. defer用于资源的释放, 会在函数返回之前进行调用. 要使用好defer最重要的是要理解return执行过程: 先给返回值赋值, 然后调用defer表达式, 最后才是返回到调用函数中. 理解了这句话, 关于defer的疑惑都能迎刃而解了.

例子

例一:

func f1() (result int) {
	defer func() {
		result++
	}()
	return 0
}

return时先将对result赋值0, 然后defer中对result++, 此时result=1; 最后返回时result=1,即调用函数获得值1.

例二:

func f2() (r int) {
	t := 5
	defer func() {
		t = t + 5
	}()
	return t
}

return时先将t的值5赋值给r(值传递); 然后defer中对加5,此时t=10,r=5; 最后返回时r=5, 即调用函数获得值5.

例三:

func f3() (r int) {
	defer func(r int) {
		r = r + 5
	}(r)
	return 1
}

return时先将1赋值给r; 然后调用defer时将r的值传递给defer函数, 注意defer函数中的r已经与函数f3返回的r不是一个变量(值传递), 因此r的修改不会影响f3返回值; 最后返回时r=1, 即调用函数获得值1.

例四:

func addCounter() {
	for count := 0; count < 2; count++ {
		defer lock.Unlock()
		//do someThing
		lock.Lock()
	}
}

将解锁放到defer中是为了防止执行任务(do someThing)时panic导致程序异常结束而未解锁。实际运行时该例子会产生死锁, 原因是(1) Muxtex不是可重入锁; (2) defer会在函数结束时执行,而不是在每一轮for循环结束时执行。正确写法如下:

func addCounter() {
	for count := 0; count < 2; count++ {
		doSomeThing()
	}
}

func doSomeThing() {
	lock.Lock()
    defer lock.Unlock()
    //do someThing
}

 

### 使用方法 Go 语言提供了 `defer` 关键字,可以注册多个延迟调用,这些调用以先进后出(FILO)的顺序在函数返回前被执行,有点类似 Java 语言中异常处理里的 `finally` 子句。`defer` 语句会立刻计算参数,但延迟函数体的执行 [^4][^5]。 示例代码如下: ```go package main import "fmt" func main() { defer fmt.Println("world") fmt.Println("hello") } ``` 上述代码会先输出 `hello`,再输出 `world`。另一个例子: ```go package main func main() { // 先进后出 defer func() { println("first") }() defer func() { println("second") }() println("function body") } ``` 该代码的输出结果为: ``` function body second first ``` ### 原理 从底层来看,`defer` 有“注册 - 执行”的全生命周期。`defer` 语句会在当前函数栈帧上创建一个 `defer` 结构体来记录要执行的函数和相关参数,这个过程就是“注册”。而在函数返回前,会按照先进后出的顺序依次执行这些 `defer` 函数,这就是“执行” [^2]。 ### 应用场景 - **资源释放**:常用于保证一些资源最终一定能够得到回收和释放。例如文件操作时,使用 `defer` 确保文件在函数结束时关闭: ```go package main import ( "fmt" "os" ) func main() { filename := "test.txt" f, err := os.Open(filename) if err != nil { panic(err) } if f != nil { defer f.Close() } // 对文件进行操作 fmt.Println("文件操作完成") } ``` - **锁的释放**:在使用互斥锁时,使用 `defer` 可以确保锁在函数结束时被释放,避免死锁: ```go package main import ( "fmt" "sync" ) var ( mu sync.Mutex count int ) func increment() { mu.Lock() defer mu.Unlock() count++ fmt.Println("Count:", count) } func main() { increment() } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值