Go 处理错误异常

2024-05-15 10:04
文章标签 go 异常 处理错误

本文主要是介绍Go 处理错误异常,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

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

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

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

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

自定义错误(Error) 

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

package mainimport ("fmt""gopkg.in/errgo.v2/errors"
)// MyError 创建一个错误结构体
type MyError struct {msg  stringcode interror
}// type error interface { Error() string }实现错误接口
func (e *MyError) Error() string {// 返回Error stringreturn 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延迟函数来完成

package mainimport ("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,因为这会使得错误处理变得复杂且难以追踪。 

package mainimport ("fmt"
)func mayPanic() {defer func() {if r := recover(); r != nil {fmt.Println("从恐慌---1中恢复过来:", r)// 错误地再次引发 panicpanic("恐慌---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

package mainimport ("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所在的函数继续执行下去的,此行将不会打印")
}

这篇关于Go 处理错误异常的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/991523

相关文章

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏

Python中 try / except / else / finally 异常处理方法详解

《Python中try/except/else/finally异常处理方法详解》:本文主要介绍Python中try/except/else/finally异常处理方法的相关资料,涵... 目录1. 基本结构2. 各部分的作用tryexceptelsefinally3. 执行流程总结4. 常见用法(1)多个e

Debian 13升级后网络转发等功能异常怎么办? 并非错误而是管理机制变更

《Debian13升级后网络转发等功能异常怎么办?并非错误而是管理机制变更》很多朋友反馈,更新到Debian13后网络转发等功能异常,这并非BUG而是Debian13Trixie调整... 日前 Debian 13 Trixie 发布后已经有众多网友升级到新版本,只不过升级后发现某些功能存在异常,例如网络转

C#文件复制异常:"未能找到文件"的解决方案与预防措施

《C#文件复制异常:未能找到文件的解决方案与预防措施》在C#开发中,文件操作是基础中的基础,但有时最基础的File.Copy()方法也会抛出令人困惑的异常,当targetFilePath设置为D:2... 目录一个看似简单的文件操作问题问题重现与错误分析错误代码示例错误信息根本原因分析全面解决方案1. 确保

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

Go之errors.New和fmt.Errorf 的区别小结

《Go之errors.New和fmt.Errorf的区别小结》本文主要介绍了Go之errors.New和fmt.Errorf的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考... 目录error的基本用法1. 获取错误信息2. 在条件判断中使用基本区别1.函数签名2.使用场景详细对

Java利用@SneakyThrows注解提升异常处理效率详解

《Java利用@SneakyThrows注解提升异常处理效率详解》这篇文章将深度剖析@SneakyThrows的原理,用法,适用场景以及隐藏的陷阱,看看它如何让Java异常处理效率飙升50%,感兴趣的... 目录前言一、检查型异常的“诅咒”:为什么Java开发者讨厌它1.1 检查型异常的痛点1.2 为什么说

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作

Go中select多路复用的实现示例

《Go中select多路复用的实现示例》Go的select用于多通道通信,实现多路复用,支持随机选择、超时控制及非阻塞操作,建议合理使用以避免协程泄漏和死循环,感兴趣的可以了解一下... 目录一、什么是select基本语法:二、select 使用示例示例1:监听多个通道输入三、select的特性四、使用se