面试题答案
一键面试defer、panic 和 recover 的作用
- defer:
- 作用:defer 语句用于延迟函数的执行,直到包含该 defer 语句的函数返回。常用于资源清理,比如关闭文件、数据库连接等操作。无论函数以何种方式结束(正常返回、发生 panic 等),defer 语句后的函数都会被执行。
- panic:
- 作用:panic 用于停止当前 goroutine 的正常执行,并开始恐慌处理流程。当发生 panic 时,程序会立即停止执行当前函数中剩余的代码,并开始执行该函数中已注册的 defer 函数。如果没有 recover 捕获 panic,程序会终止并打印堆栈跟踪信息。
- recover:
- 作用:recover 用于在 defer 函数中捕获 panic,从而阻止程序崩溃。如果在 defer 函数中调用 recover,并且当前 goroutine 正处于恐慌状态,recover 会返回传递给 panic 的值,同时恢复正常执行。
协同机制
- panic 触发:当在代码中调用 panic 时,正常执行流被打断,控制权交给 defer 函数。
- defer 执行:函数中的 defer 函数按照后进先出(LIFO)的顺序依次执行。
- recover 捕获:如果在 defer 函数中调用 recover 并且捕获到 panic,程序可以从 panic 中恢复并继续执行,否则程序会崩溃。
复杂业务场景示例
假设我们有一个复杂业务场景,需要打开文件、读取内容并进行一些计算,同时确保在出现错误时文件能够正确关闭。
package main
import (
"fmt"
)
func complexBusiness() {
file, err := openFile("example.txt")
if err != nil {
panic(err)
}
defer closeFile(file)
data, err := readFile(file)
if err != nil {
panic(err)
}
result := calculate(data)
fmt.Println("计算结果:", result)
}
func openFile(filename string) (*File, error) {
// 这里模拟打开文件的操作
// 实际中可以使用 os.Open 等函数
if filename == "example.txt" {
return &File{}, nil
}
return nil, fmt.Errorf("无法打开文件")
}
func closeFile(file *File) {
// 这里模拟关闭文件的操作
fmt.Println("文件已关闭")
}
func readFile(file *File) ([]byte, error) {
// 这里模拟读取文件的操作
// 实际中可以使用 file.Read 等函数
return []byte("123"), nil
}
func calculate(data []byte) int {
// 这里模拟计算操作
sum := 0
for _, v := range data {
sum += int(v - '0')
}
return sum
}
type File struct{}
在这个示例中:
openFile
和readFile
函数可能会返回错误,当发生错误时,我们使用panic
抛出错误。- 通过
defer closeFile(file)
确保无论是否发生错误,文件都会被关闭。 - 如果需要在更高层次捕获这些错误并进行处理,可以在调用
complexBusiness
的地方使用recover
。例如:
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("捕获到 panic:", r)
}
}()
complexBusiness()
}
在 main
函数中,通过匿名的 defer 函数使用 recover
捕获 complexBusiness
函数中可能发生的 panic,避免程序崩溃,并能对错误进行适当处理。