Derick
822 words
4 minutes
Go语言教程:深入理解defer、panic和recover

在Go语言中,deferpanicrecover是三个非常重要的关键字,它们在处理错误和资源管理方面起着至关重要的作用。本文将通过几个示例代码,深入浅出地讲解这三个关键字的用法和注意事项。

示例1:defer的基本用法#

package main

import "fmt"

func main() {
	defer fmt.Println("first defer")
	for i := 0; i < 3; i++ {
		defer fmt.Printf("defer in for [%d]\\n", i)
	}
	defer fmt.Println("last defer")
}

解析#

  1. defer的执行顺序
    • defer语句会将其后的函数调用推迟到包含它的函数即将返回的时候执行。
    • 多个defer语句的执行顺序是后进先出(LIFO)。
  2. 代码执行顺序
    • main函数开始执行,首先注册defer fmt.Println("first defer")
    • 进入for循环,依次注册defer fmt.Printf("defer in for [%d]\\n", i),其中i的值分别为0、1、2。
    • 注册defer fmt.Println("last defer")
    • main函数即将返回时,按照后进先出的顺序执行所有的defer语句。

输出结果#

last defer
defer in for [2]
defer in for [1]
defer in for [0]
first defer

示例2:panic和recover的用法#

package main

import (
	"errors"
	"fmt"
)

func main() {
	fmt.Println("Enter function main.")

	defer func() {
		fmt.Println("Enter defer function.")

		// recover函数的正确用法。
		if p := recover(); p != nil {
			fmt.Printf("panic: %s\\n", p)
		}

		fmt.Println("Exit defer function.")
	}()

	// recover函数的错误用法。
	fmt.Printf("no panic: %v\\n", recover())

	// 引发panic。
	panic(errors.New("something wrong"))

	// recover函数的错误用法。
	p := recover()
	fmt.Printf("panic: %s\\n", p)

	fmt.Println("Exit function main.")
}

解析#

  1. panic
    • panic用于引发一个恐慌,终止当前函数的执行,并开始沿着调用栈向上回溯,直到遇到recover或程序崩溃。
  2. recover
    • recover用于终止panic的回溯,恢复正常的执行流程。它只能在defer函数中有效。
  3. 代码执行顺序
    • main函数开始执行,打印"Enter function main."
    • 注册defer函数。
    • 调用recover(),此时没有panic,返回nil
    • 引发panic,错误信息为"something wrong"
    • defer函数被调用,recover捕获到panic,打印错误信息。
    • defer函数执行完毕,main函数继续执行。

输出结果#

Enter function main.
no panic: <nil>
Enter defer function.
panic: something wrong
Exit defer function.

示例3:panic的正确和错误用法#

package main

import (
	"errors"
	"fmt"
)

func main() {
	fmt.Println("Enter function main.")
	caller()
	fmt.Println("Exit function main.")
}

func caller() {
	fmt.Println("Enter function caller.")
	panic(errors.New("something wrong")) // 正例。
	panic(fmt.Println)                   // 反例。
	fmt.Println("Exit function caller.")
}

解析#

  1. panic的正确用法
    • panic(errors.New("something wrong")):引发一个带有错误信息的panic
  2. panic的错误用法
    • panic(fmt.Println)fmt.Println是一个函数,不是错误信息或字符串,使用不当。
  3. 代码执行顺序
    • main函数开始执行,打印"Enter function main."
    • 调用caller函数。
    • caller函数引发panic,错误信息为"something wrong",程序终止。

输出结果#

Enter function main.
Enter function caller.
panic: something wrong

总结#

通过以上示例,我们可以总结出以下几点:

  1. defer
    • 用于延迟函数的执行,直到包含它的函数即将返回时执行。
    • 多个defer语句按照后进先出的顺序执行。
  2. panic
    • 用于引发一个恐慌,终止当前函数的执行,并开始沿着调用栈向上回溯。
  3. recover
    • 用于终止panic的回溯,恢复正常的执行流程。只能在defer函数中有效。

通过理解和掌握deferpanicrecover的用法,可以更好地处理Go语言中的错误和资源管理,提高代码的健壮性和可维护性。

Go语言教程:深入理解defer、panic和recover
https://blog.ithuo.net/posts/go-language-defer-panic-recover/
Author
Derick
Published at
2022-05-19