Go 处理错误&异常

在Go语言中错误和异常是两个完全不同的概念,错误指的是可能出现问题的地方出现了问题,而异常指的是不该出现问题的地方出现了问题

从Go语言的机制上讲错误和异常就是error 和panic的区别

  • 错误(Error):程序中预期会发生的错误,预料之中

  • 异常(Panic):不该出现问题的地方出现了问题,预料之外

  • 错误是业务的一部分,而异常不是,异常是我们不想要的

自定义错误(Error)

在自定义错误中,只需要定义结构体来实现Error()方法即可

Go 复制代码
package main

import (
	"fmt"
	"gopkg.in/errgo.v2/errors"
)

// MyError 创建一个错误结构体
type MyError struct {
	msg  string
	code int
	error
}

// type error interface { Error() string }实现错误接口
func (e *MyError) Error() string {
	// 返回Error string
	return fmt.Sprintf("错误信息:%s,错误代码:%d,c错误值%s\n", e.msg, e.code, e.error)

}
func (e *MyError) print() bool {
	return true

}

func test(i int) (int, error) {
	if i != 0 {
		// 使用自定义的Error进行返回
		return i, &MyError{
			msg:   "输入的值不等于0",
			code:  500,
			error: errors.New("3333333"),
		}
	}
	// 正常结果
	return i, nil
}

func main() {
	i, err := test(1)
	if err != nil {
		// 使用断言判断err类型
		my_err, ok := err.(*MyError)
		if ok {
			if my_err.print() {
				// 处理err的子逻辑
			}
		}
		fmt.Println(my_err.msg, my_err.code, my_err.error)
	}
	fmt.Println(i)
}

异常(Panic)

Go语言中没有try...catch语句,如果需要处理异常则需要使用panic抛出异常,recover来接收处理异常

在使用panic和recover来处理异常的时候必须要结合defer延迟函数来完成

Go 复制代码
package main

import (
	"fmt"
)

func testPanic(i int) {

	// 出去函数的时候处理这里面可能发生的panic
	// recover func recover() any 返回panic传递的值
	// panic   func panic(v any)
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("捕获到的panic异常---------->", err)
		}
	}()

	if i > 0 {
		panic("这是运行过程中出现异常的------panic")
	}
}
func main() {
	testPanic(1)
}

处理Panic后再次出现Panic怎么办

在 Go 语言中,deferrecover 是用于异常处理的两个关键字。recover 用于捕获 panic 产生的异常,防止程序因为 panic 而崩溃,并且可以恢复程序的执行流程。defer 允许你在函数退出时执行代码,无论函数是正常结束还是因为调用了 panic 或者遇到了其他异常。

当你在一个使用了 recoverdefer 语句中再次引发 panic,recover 可以捕获到这个 panic,但是这将导致程序进入一个异常的递归状态,因为 recover 已经处于处理 panic 的状态。在实际应用中,你通常不应该在已经调用了 recoverdefer 语句中再次引发 panic,因为这会使得错误处理变得复杂且难以追踪。

Go 复制代码
package main

import (
	"fmt"
)

func mayPanic() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("从恐慌---1中恢复过来:", r)
			// 错误地再次引发 panic
			panic("恐慌---2")
		}
	}()

	panic("恐慌---1")
}

func main() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("从恐慌中恢复过来:", r)
		}
	}()

	mayPanic()
	fmt.Println("如果mayPanic没有恢复,将不会打印此信息,因为出现恐慌1的过程中再次出现恐慌")
	/*
		mayPanic 函数中的 defer 语句尝试捕获一个 panic,然后错误地再次引发 panic。
		然而,由于 recover 已经在处理一个 panic,再次引发 panic 将不会被捕获,程序将终止
	*/
}

为了避免这种情况,你应该避免在 recover 内部再次引发 panic。如果你需要处理错误或 panic 产生的结果,你可以直接返回错误或进行其他类型的处理,而不是再次 panic。

正确的错误处理方式可能包括记录日志、清理资源、向调用者返回错误等。在实际应用中,你应该仔细设计错误处理逻辑,确保程序的稳定性和可维护性。

处理多个 panic

处理多个 panic 的情况通常涉及到多个 defer 语句

在 Go 语言中,处理多个 panic 的情况通常涉及到多个 defer 语句。每个 defer 语句都是独立的,并且按照它们出现的逆序(即最后一个 defer 先执行)来执行。这意味着你可以在不同的 defer 块中使用 recover 来捕获并处理 panic

如果一个函数中有多个地方可能引发 panic,并且你希望对每个 panic 进行特定的处理,你可以在每个潜在的 panic 点后面放置一个 defer 块,并在其中使用 recover

Go 复制代码
package main

import (
	"fmt"
)

func mayPanic1(str string) {

	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("从恐慌中恢复 %s\n", r)
		}
	}()

	// 模拟可能发生 panic 的代码
	//出现Panic后是不会继续执行Panic所在的函数继续执行下去的
	panic(str)
}
func mayPanic2(str string) {

	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("从恐慌中恢复 %s\n", r)
		}
	}()

	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("(defer recover的顺序是按照它们出现的逆序执行的)从恐慌中恢复 %s\n", r)
		}
	}()

	// 模拟可能发生 panic 的代码
	//出现Panic后是不会继续执行Panic所在的函数继续执行下去的
	panic(str)
}
func mayPanic3(str string) {
	// 模拟可能发生 panic 的代码
	//出现Panic后是不会继续执行Panic所在的函数继续执行下去的
	panic(str)
}
func main() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("从恐慌中恢复过来: %v\n", r)
		}
	}()
	mayPanic1("恐慌--A")
	fmt.Println("由于恐慌--A已恢复,将打印此行")

	mayPanic2("恐慌--B")
	fmt.Println("由于恐慌--B已恢复,将打印此行")

	mayPanic3("恐慌--C")
	fmt.Println("出现Panic后是不会继续执行Panic所在的函数继续执行下去的,此行将不会打印")
}
相关推荐
2501_941875284 小时前
从配置中心到动态管理的互联网工程语法演进与多语言实践分享
开发语言·python
hfywmsj5 小时前
广州餐饮铺位招租决策模型:多因子选址系统设计
开发语言·人工智能·python·广州餐饮铺位招租
vx-Biye_Design5 小时前
SSM伴侣动物伴护星小程序06330-计算机课程设计、毕业设计
spring boot·后端·elasticsearch·小程序·架构·课程设计·idea
努力的lpp7 小时前
php反序列化一(大白话版)
开发语言·web安全·php·ctf·反序列化
2分钟速写快排7 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
菜鸟~noob2337 小时前
【电子战】第03篇:CFAR(恒虚警)处理【含matlab代码】
开发语言·matlab
面向Google编程7 小时前
Apache Iceberg Variant 类型:v3 半结构化数据不再「二选一」
大数据·后端
jason成都8 小时前
Spring WebFlux 适配达梦新方案|dm‑r2dbc:Netty 异步传输的实验性 R2DBC 驱动
java·后端·spring
泡海椒8 小时前
内置SPI函数库详解:JQuick-Java Builtin工具类实战用法
java·开发语言·python
hqyjzsb8 小时前
零 AI 项目经验,学 Python 转型 AI 的正确顺序是什么?
开发语言·人工智能·python·算法·职场和发展·数据挖掘·数据分析