MST

星途 面试题库

面试题:Go语言错误处理中的defer、panic和recover如何协同工作

描述defer、panic和recover在Go语言错误处理中的作用及协同机制,在一个可能会引发错误的复杂业务场景中,如何合理使用这几个特性进行有效的错误处理和资源清理,举例并给出代码实现。
48.2万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

defer、panic 和 recover 的作用

  1. defer
    • 作用:defer 语句用于延迟函数的执行,直到包含该 defer 语句的函数返回。常用于资源清理,比如关闭文件、数据库连接等操作。无论函数以何种方式结束(正常返回、发生 panic 等),defer 语句后的函数都会被执行。
  2. panic
    • 作用:panic 用于停止当前 goroutine 的正常执行,并开始恐慌处理流程。当发生 panic 时,程序会立即停止执行当前函数中剩余的代码,并开始执行该函数中已注册的 defer 函数。如果没有 recover 捕获 panic,程序会终止并打印堆栈跟踪信息。
  3. recover
    • 作用:recover 用于在 defer 函数中捕获 panic,从而阻止程序崩溃。如果在 defer 函数中调用 recover,并且当前 goroutine 正处于恐慌状态,recover 会返回传递给 panic 的值,同时恢复正常执行。

协同机制

  1. panic 触发:当在代码中调用 panic 时,正常执行流被打断,控制权交给 defer 函数。
  2. defer 执行:函数中的 defer 函数按照后进先出(LIFO)的顺序依次执行。
  3. 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{}

在这个示例中:

  1. openFilereadFile 函数可能会返回错误,当发生错误时,我们使用 panic 抛出错误。
  2. 通过 defer closeFile(file) 确保无论是否发生错误,文件都会被关闭。
  3. 如果需要在更高层次捕获这些错误并进行处理,可以在调用 complexBusiness 的地方使用 recover。例如:
func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("捕获到 panic:", r)
        }
    }()
    complexBusiness()
}

main 函数中,通过匿名的 defer 函数使用 recover 捕获 complexBusiness 函数中可能发生的 panic,避免程序崩溃,并能对错误进行适当处理。