Golang defer关键字

ops/2024/11/18 14:54:08/

defer特性

1.关键字defer 用于注册延迟调用

2.这些调用直到return 前才被执行。因此,可以用来做资源清理

3.多个defer语句,按先进后出的方式执行

4.defer语句中的变量,在defer生命时就决定了

defer用途

1.关闭文件句柄

2.锁资源释放

3.数据库连接释放

defer用例

1.多个defer输出顺序
func main() {for i := 0; i < 3; i++ {defer fmt.Println(i) // 1. 这三个 defer 语句会按照 i=0, i=1, i=2 的顺序被推入栈中。}fmt.Println("循环结束") // 2. 循环结束,打印 "循环结束"。if true {defer fmt.Println("条件语句中的 defer") // 3. 这个 defer 语句被推入栈中。}defer fmt.Println("最后的 defer") // 4. 这个 defer 语句被推入栈中。fmt.Println("main 函数执行中") // 5. 打印 "main 函数执行中"。
}//结果
//循环结束
//main 函数执行中
//最后的 defer
//条件语句中的 defer
//2
//1
//0
2.defer遇到循环
//第一个例子
package mainimport "fmt"type Test struct {name string
}func (t *Test) Close() {fmt.Println(t.name, " closed")
}
func main() {ts := []Test{{"a"}, {"b"}, {"c"}}for _, t := range ts {defer t.Close()}
}//结果:c closed 
//c closed
//c closed
//第二个例子
package mainimport "fmt"type Test struct {name string
}func (t *Test) Close() {fmt.Println(t.name, " closed")
}
func Close(t Test) {t.Close()
}
func main() {ts := []Test{{"a"}, {"b"}, {"c"}}for _, t := range ts {defer Close(t)}
}
//结果
//c  closed
//b  closed
//a  closed

第一个例子中,当defer语句被执行时,它都会捕获t当前值的副本,并不是t的地址。由于t是在循环遍历的,每次迭代都会创建t的副本,而不是t的地址。由于t是在循环中逐一遍历的,每次迭代都会创建t的新副本。因此当main函数结束时,defer语句会按照后进先出的顺序执行,但是每个defer调用都会打印循环结束时t的最终副本,即“c”。

第二个例子中的close函数接受一个Test类型的参数,并且调用这个参数的Close方法。由于Close是一个单独的函数,它接收t的副本作为参考。当defer调用Close(t)时,它传递了t的当前值的副本给Close函数。这意味着每个defer调用都捕获了循环中t的当前值的副本。 

3.defer +recover 捕获异常
package mainimport "fmt"func safeDivide(a, b int) (int, error) {defer func() {if r := recover(); r != nil {fmt.Println("Recovered from panic:", r)}}()if b == 0 {return 0, fmt.Errorf("cannot divide by zero")}return a / b, nil
}func main() {result, err := safeDivide(10, 0)if err != nil {fmt.Println("Error:", err)}fmt.Println("Result:", result)
}
4.defer 遇到闭包
package mainimport "fmt"func main() {var whatever [5]struct{}for i := range whatever {defer func() { fmt.Println(i) }()}
}
//结果
//4
//4
//4
//4
//4

这是因为闭包用到的变量i在执行时就已经变成4了,所以输出全是4

注意事项

注意事项

  1. 性能:过度使用 defer 可能会影响性能,因为每个 defer 调用都会创建额外的栈帧。

  2. 控制流defer 语句的执行顺序可能与直觉相反,需要仔细设计以确保逻辑正确。

  3. 错误处理defer 语句中的错误处理代码应该能够处理所有可能的错误情况。

  4. 嵌套使用:嵌套使用 defer 时,确保外层的 defer 能够正确处理内层可能抛出的错误。


http://www.ppmy.cn/ops/134730.html

相关文章

《C陷阱与缺陷》

文章目录 1、【词法陷阱】1.1 符号与组成符号间的关系1.1 与 1.3 y x/*p 与 y x/(*p)&#xff0c;a-1 与 a - 1 与 a -1, 老版本编译器的处理是不同的&#xff0c;严格的ANSI C则会报错1.4 十进制的 076&#xff0c;会被处理为八进制&#xff0c;ANSI C禁止这种用法&#x…

【Go】-bufio库解读

目录 Reader和Writer接口 bufio.Reader/Writer 小结 其他函数-Peek、fill Reader小结 Writer Scanner结构体 缓冲区对于网络数据读写的重要性 Reader和Writer接口 在net/http包生成的Conn 接口的实例中有两个方法叫做Read和Write接口 type Conn interface {Read(b []b…

AI 产品的四层架构:开启智能未来的密码

在人工智能飞速发展的今天&#xff0c;AI产品正逐渐渗透到我们生活的方方面面&#xff0c;从智能助手到自动驾驶&#xff0c;AI的应用正不断拓宽我们的想象边界。但构建一个成功的AI产品并非易事&#xff0c;它需要深入理解AI产品的架构和开发流程。 AI对我们来说已经不算是新鲜…

高效协作:前后端合作规范与应对策略优化

1 背景 在软件开发领域&#xff0c;前后端协作的紧密程度对项目进度与质量具有决定性影响。然而&#xff0c;实践中常出现前端找不到后端接口、调试效率低下、后端依赖前端反馈修正问题以及职责界限模糊等问题&#xff0c;这些问题严重阻碍了开发效率与产品稳定性。因此&#…

学生公寓管理系统

学生公寓管理系统 目 录 引言 5 1.1 编写目的 5 1.2 文档书写约定 5 1.3 术语定义 5 1.4 参考资料 5业务系统流程及功能描述 5 2.1 系统总体目标 6 2.2 系统涉及角色 6 2.3 系统框架图 6 2.4 学生公寓管理 6 2.4.1 业务流程 6 2.4.2 涉及角色 6 2.4.3 数据流向 7 2.4.4 样例报…

微服务各组件整合

nacos 第一步&#xff0c;引入依赖 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency> 第二步&#xff0c;增加配置 spring:application:name: …

Linux基本指令(中)(2)

文章目录 前言一、echo二、cat三、more四、less五、head六、tail七、date八、cal九、find十、whoami十一、clear总结 前言 承上启下&#xff0c;我们再来看看另外一些常用的基础指令吧&#xff01; 一、echo 语法&#xff1a;echo [选项] [字符串] 功能&#xff1a;在终端设备上…

段探测的研究

在介绍今天的内容之前&#xff0c;我们先要知道一些前置的知识 跳过繁琐的介绍&#xff0c;我们单刀直入&#xff0c;介绍一个划时代的CPU 8086 8086 从8086开始&#xff0c;CPU扩展到了16位&#xff0c;地址的位宽扩展到了20位&#xff0c;自此之后我们现在所熟知的计算机结…