go的defer机制

defer的底层机制

为栈操作,栈是一个先进后出的数据结构

func main() {
    fmt.Println("reciprocal")

    for i := 0; i < 10; i++ {
        defer fmt.Println(i)
    }
}

运行结果
reciprocal
9
8
7
6
5
4
3
2
1
0

defer拷贝机制

以下已经发生压栈发生值拷贝数据不再会发生变化

func test() int {
	var i = 1
	defer func(i int) {
		fmt.Println("数据压栈已压栈数据不会在发生变化", i)
	}(i)
	i++
	return i
}

运行结果

数据压栈已压栈数据不会在发生变化 1

函数返回值 2

deferreturn的返回时机(执行顺序)

根据defer内的变量为匿名函数,还是命名函数。函数的返回数据会有差距

1. 计算并赋值返回值

• 对于匿名返回值的函数,return 语句先会计算并生成返回值,并将其赋值给一个临时变量。

• 对于命名返回值的函数,return 语句会将结果赋值给命名的返回变量,这个变量在函数开始时就已经声明。

2. 执行 defer 语句

• defer 语句中的函数在 return 语句执行后被调用,但它们的执行顺序是后进先出 (Last In First Out, LIFO) 的。

• defer 函数可以操作命名返回值,从而可能修改最终的返回值。

3. 返回结果

• 在 defer 函数执行完后,返回最终的结果。

实践匿名函数

func main() {
	fmt.Println(Anonymous())
}

func Anonymous() int {
	var i int
	defer func() {
		i++
		fmt.Println("defer2 value is ", i)
	}()

	defer func() {
		i++
		fmt.Println("defer1 in value is ", i)
	}()

	return i
}

结果

defer1 in value is  1

defer2 value is  2

0

执行过程

        1. 函数执行到 return i 时,i 的值是 0。

        2. 执行 defer 语句,先执行 defer1,然后执行 defer2,此时 i 变为 2,但 return 的返回值已                固定为 0。

        3. 最终返回值为 0。

实践命名返回值的函数

func main() {
	fmt.Println(HasName())
}

func HasName() (j int) {
	defer func() {
		j++
		fmt.Println("defer2 in value", j)
	}()

	defer func() {
		j++
		fmt.Println("defer1 in value", j)
	}()

	return j
}

结果
defer1 in value 1
defer2 in value 2
2

执行过程

1. 函数执行到 return j 时,j 的初始值为 0。

2. 执行 defer 语句,先执行 defer1,j 变为 1,再执行 defer2,j 变为 2。

3. 最终返回值为 2,因为 defer 修改了命名返回值 j。

总结

匿名返回值函数:return 语句计算出返回值并存储在临时变量中,随后执行 defer 函数,但 defer 对返回值的修改不会影响最终返回值。

命名返回值函数:return 语句返回命名的返回变量,defer 函数能够修改这个变量,因此它会影响最终返回值。

defer 执行顺序的规则

1. defer 的参数在 defer 语句处计算。

2. defer 函数在函数返回时按照后进先出的顺序执行。

3. defer 函数可以读写返回函数的命名返回值。

defer 的使用场景:

1. 关闭资源

在处理文件、数据库连接、网络连接等需要关闭的资源时,defer 确保资源在使用完毕后被正确关闭,即使中间发生了错误。

2. 解锁资源

当使用 sync.Mutex 等锁机制时,defer 确保锁在临界区代码执行完毕后被解锁,从而避免死锁情况的发生。defer 释放分布式锁,防止死锁

3.记录日志或执行收尾工作

defer 可以用来记录函数的退出状态,或者在函数结束前执行一些收尾操作,例如日志记录或计时。

4. 处理错误和恢复(recover)

在可能会引发 panic 的代码中,defer 可以用来捕获和恢复错误,防止程序崩溃。

5. 清理临时状态

在函数内创建了一些临时状态或变量,需要在函数结束时清理时,defer 可以确保这些清理操作被执行。

引用

详解defer实现机制(附上三道面试题,我不信你们都能做对)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值