阐述一下Go的defer原理 ?

在Go语言中,defer关键字用于在函数返回前执行一段代码或调用一个清理函数。这对于处理像文件关闭、解锁或者返回一些资源到资源池等操作非常有用。

当你在一个函数内部调用defer关键字,Go实际上会把它后面的函数(通常是一个匿名函数或清理函数)压入一个栈中。当外部函数准备返回时,Go会按照后进先出(LIFO)的顺序调用并执行这个栈中的所有函数。

需要注意的是,defer语句的参数会在defer语句处就计算好,而不是在外部函数返回时才计算。这意味着下面的代码会首先打印出0

func main() {
    i := 0
    defer fmt.Println(i)
    i++
    return
}

defer的使用可以简化一些代码的复杂度,比如在异常处理和资源清理等场景。例如,当打开一个文件进行操作后,可以立即调用defer来确保文件最后被关闭:

func main() {
    file, err := os.Open("file.go")
    if err != nil {
        // handle the error here
        return
    }
    defer file.Close()
    // continue to work with file
}

在这个例子中,不论后续的代码路径如何,file.Close()总会在main()函数结束之前被调用到,这样就确保了资源的正确释放。