defer
- defer 关键字用来声明一个延迟调用的函数, 该函数可以是匿名函数也可以是具名函数
- 延迟函数执行时间(位置),方法return之后,返回参数到调用方法之前
- 延迟函数可以在方法返回之后改变函数的返回值
- 在方法结束(正常返回,异常结束)都会去调用defer声明的延迟函数,可以有效避免因异常导致的资源无法释放的问题
- 可以指定多个defer 延迟函数,多个延迟函数执行顺序后进先出
- defer 通常用于资源释放、异常捕获等多个场景,例如:关闭连接,关闭文件
- defer 与 recover 配合可以实现异常捕获与逻辑处理
- 不建议在for循环中使用defer
defer快速入门
package _case
import "fmt"
// DeferCase1 defer 关键字声明一个延迟调用函数
// 执行顺序为后进先出
func DeferCase1() {
fmt.Println("开始执行DeferCase1")
defer func() {
fmt.Println("调用了匿名函数1")
}()
defer f1()
defer func() {
fmt.Println("调用了匿名函数2")
}()
fmt.Println("DeferCase1执行结束")
}
func f1() {
fmt.Println("调用了具名函数f1")
}
打印结果
开始执行DeferCase1
DeferCase1执行结束
调用了匿名函数2
调用了具名函数f1
调用了匿名函数1
defer实现参数预计算
// DeferCase2 参数预计算
func DeferCase2() {
i := 1
defer func(j int) {
fmt.Println("defer j", j)
}(i + 1)
//闭包
defer func() {
fmt.Println("defer i", i) //匿名函数访问外部函数变量
}()
i = 99
fmt.Println("i", i)
}
打印结果
i 99
defer i 99
defer j 2
defer 函数执行在return之后
// DeferCase3 defer函数执行在return之后
func DeferCase3() {
i, j := f2()
fmt.Printf("i: %d, j: %d, g: %d\n", i, *j, g)
}
var g = 100
func f2() (int, *int) {
defer func() {
g = 200
}()
fmt.Println("f2 g :", g)
return g, &g
}
打印结果
f2 g : 100
i: 100, j: 200, g: 200
defer异常捕获
// ExceptionCase defer 实现异常捕获
func ExceptionCase() {
defer func() {
}()
fmt.Println("开始执行ExceptionCase方法")
panic("ExceptionCase抛出异常")
fmt.Println("ExceptionCase方法这些结束")
}
//实现异常捕获
// ExceptionCase defer 实现异常捕获
func ExceptionCase() {
defer func() {
//捕获异常, 恢复协程
err := recover()
//异常处理
if err != nil {
fmt.Println("异常处理 defer recover")
}
}()
fmt.Println("开始执行ExceptionCase方法")
panic("ExceptionCase抛出异常")
fmt.Println("ExceptionCase方法这些结束")
}
打印结果
开始执行ExceptionCase方法
异常处理 defer recover
defer 读取文件释放资源
// FileReadCase 文件读取,资源释放
func FileReadCase() {
file, err := os.Open("E:\\test.txt")
if err != nil {
log.Fatal(err)
}
//通过defer调用资源释放的方法
defer func() {
file.Close()
fmt.Println("释放文件")
}()
buf := make([]byte, 1024)
for {
n, err := file.Read(buf)
if err != nil && err != io.EOF {
log.Fatal(err)
}
if n == 0 {
break
}
fmt.Println(buf[:n])
}
}
打印结果
[104 101 108 108 111 32 119 111 114 108 100 13 10]
释放文件
recover
- Go语言的内建函数,可以让进入待机流程中的 goroutine 恢复过来
- recover 仅在延迟函数 defer 中有效,在正常的执行过程中,调用 recover 会返回 nil 并且没有其他效果
- 如果当前的 goroutine 出现 painc,调用 recover 可以捕获到 panic 的输入值, 并且恢复正常的执行
panic
- Go语言的一种异常机制
- 可以通过 panic 函数主动抛出异常