Golang 异常处理

前言

Go语言中,"异常"的概念与其他语言如Java或Python中的不太相同。Go没有提供传统意义上的try-catch机制来捕获异常。相反,Go使用错误作为其错误处理的主要方式
感觉很麻烦,到处都要处理…,没有传统的try-catch好用

常见异常的处理

  1. 向上一级抛,示例
func SomeFunction() (int, error) {
   
    // ... function logic ...

    // When an error occurs
    if somethingWentWrong {
   
        return 0, errors.New("something went wrong")
    }

    // No error occurred
    return result, nil
}

func main() {
   
    result, err := SomeFunction()
    if err != nil {
   
        // handle the error
        fmt.Println("Error occurred:", err)
    } else {
   
        // no error, use the result
        fmt.Println("Success:", result)
    }
}
  1. 中断程序
    一般用于初始化
package main

import (
	"fmt"
	"os"
)

func init() {
   
	// 读取不到配置文件
	_, err := os.ReadFile("config.yaml")
	if err != nil {
   
		panic(err.Error()) // panic 函数会立即停止当前函数的执行
		// 或者使用 log.Fatalln("配置文件读取失败")
	}
}

func main() {
   
	fmt.Println("Hello, World!")
}

这个例子中,panic函数会立即停止当前函数的执行,然后逐层向上返回,直到被程序的顶层调用者捕获,这时程序通常会崩溃,抛出panic:panic: open config.yaml: The system cannot find the file specified.
或者使用 log.Fatalln(),它里面会执行os.Exit(1),程序也会立马终止,但可以自定义提示信息

  1. 恢复程序
    在第2步的基础上,可以通过defer语句配合recover函数来捕获和处理这种类型的错误
    这也是用到的比较多的

recover 是一个内置函数,用于"捕获"或"恢复"一个panicrecover只有在defer语句中调用时才有效。如果在没有发生panic的情况下调用recover,或者不在defer语句中调用recover,它将不会有任何效果,并返回nil

当代码执行到panic时,正常的函数执行流程会被中断,然后Go运行时会开始逐层向上回退(unwind)调用栈,运行每一层的defer语句。如果在这个过程中某个defer语句中调用了recoverrecover会捕获到panic的值,并且阻止panic继续向上传播。这样,程序就有机会从错误中恢复,继续执行

看个例子:

package main

import "fmt"

func mayPanic() {
   
	panic("a problem")
}

func main() {
   
	defer func() {
   
		if r := recover(); r != nil {
   
			// 处理错误
			fmt.Println("Recovered. Error:\n", r)
			// 处理完错误,然后下面执行正常逻辑代码
			// 正常代码
		}
	}()

	mayPanic()

	// 这行代码只有在recover成功捕获panic后才会运行
	fmt.Println("After mayPanic()")
}

mayPanic函数调用panic,此时main函数中的defer语句会被执行。在这个defer语句中,recover函数被调用并捕获了panic的值。因此,程序从panic中恢复过来,而不是终止执行。然后程序会继续执行main函数中defer之后的代码。如果没有recover捕获panic,程序将会终止,并打印出panic信息和堆栈跟踪
处理错误时,可能希望查看具体是哪里执行出错,可以使用

fmt.Println(string(debug.Stack()))

它会打印详细的调用栈信息,可以具体到出错的行

进一步,我们单独弄个函数来处理

package main

import "fmt"

func mayPanic() {
   
	panic("a problem")
}

func dealWithPanic() {
   
	defer func() {
   
		if r := recover(); r != nil {
   
			// 处理错误
			fmt.Println("Recovered. Error:\n", r)
		}
	}()
	mayPanic()
}

func main() {
   
	dealWithPanic()
	// 正常要处理的代码
	fmt.Println("After mayPanic()")
}

相关推荐

  1. Golang 异常处理

    2024-01-10 17:42:03       33 阅读
  2. 后端异常处理:全局异常处理器

    2024-01-10 17:42:03       25 阅读
  3. 题目 异常处理

    2024-01-10 17:42:03       32 阅读
  4. WPF 全局异常处理

    2024-01-10 17:42:03       41 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-10 17:42:03       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-10 17:42:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-10 17:42:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-10 17:42:03       20 阅读

热门阅读

  1. rhel 9 mysql 无法远程访问(linux)

    2024-01-10 17:42:03       39 阅读
  2. Redis 常用的数据类型及用法

    2024-01-10 17:42:03       34 阅读
  3. XSS(跨站脚本攻击)漏洞介绍

    2024-01-10 17:42:03       37 阅读
  4. 奇怪的事情记录:外置网卡和外置显示器不兼容

    2024-01-10 17:42:03       47 阅读
  5. vue element plus Border 边框

    2024-01-10 17:42:03       43 阅读
  6. redis 相关面试题(一)

    2024-01-10 17:42:03       35 阅读
  7. MySQL优化:12种提升SQL执行效率的有效方法

    2024-01-10 17:42:03       36 阅读
  8. 开发基础----牛客SQL速成

    2024-01-10 17:42:03       40 阅读
  9. 2_单列模式_懒汉式单例模式

    2024-01-10 17:42:03       36 阅读