【Golang】深入解读Go语言中的错误(error)与异常(panic)

在这里插入图片描述

✨✨ 欢迎大家来到景天科技苑✨✨

🎈🎈 养成好习惯,先赞后看哦~🎈🎈

🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,Golang开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。

所属的专栏:Go语言开发零基础到高阶实战
景天的主页:景天科技苑

在这里插入图片描述

文章目录

  • Go语言中的错误与异常
    • 1. Go语言错误 error
      • (1)自定义错误
        • 1. 使用errors.New()
        • 2.使用fmt.Errorf()
        • 3. 综合案例
      • (2)自定义错误类型(难点)
        • 1、定义一个结构体
        • 2、为该结构体创建个方法,实现go内置error接口中的Error方法
        • 3、创建个方法测试
        • 4、main方法中写逻辑
    • 2. Go语言的异常处理机制
      • (1)使用panic
      • (2)使用recover
        • 1. recover案例展示
        • 2. recover结合多个defer执行顺序

Go语言中的错误与异常

在Go语言编程中,错误和异常处理是非常重要的一部分。Go语言通过其独特的错误处理机制和异常处理模型,提供了一种既清晰又高效的方式来处理程序运行时的错误和异常情况。

错误:指的是程序中预期会发生的结果,预料之中

打开一个文件:文件正在被占用,可知的。

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

调用一个对象,发现这个对象是个空指针对象,发生错误。

错误是业务的一部分,而异常不是。

go语言开发过程中遇到最多的代码,就是error。

需要将所有的错误情况都考虑到,并写到你的代码中。

1. Go语言错误 error

鼓励工程师在代码中显式的检查错误,而非忽略错误。

错误是开发中必须要思考的问题

  • 某些系统错误 ,文件被占用,网络有延迟
  • 人为错误:核心就是一些不正常的用户会怎么来给你传递参数,sql注入

在实际工程项目中,
我们希望通过程序的错误信息快速定位问题,但是又不喜欢错误处理代码写的冗余而又啰嗦。
Go语言没有提供像Java. c#语言中的try…catch异常处理方式,
而是通过函数返回值逐层往上抛, 如果没有人处理这个错误,程序就终止 panic

这种设计,鼓励工程师在代码中显式的检查错误,而非忽略错误。
好处就是避免漏掉本应处理的错误。但是带来一个弊端,让代码繁琐。

Go中的错误也是一种类型。错误用内置的error类型表示。就像其他类型的,如int, float64。
错误值可以存储在变量中,从函数中返回,传递参数 等等。

代码示例:

package mainimport ("fmt""os"
)// 错误是开发中必须要思考的问题
// - 某些系统错误 ,文件被占用,网络有延迟
// - 人为错误:核心就是一些不正常的用户会怎么来给你传递参数,sql注入
func main() {//工作目录是指在执行程序时,操作系统认为当前正在工作的目录。//一般情况下,我们通过在终端或文件浏览器中打开文件时所处的目录就是当前工作目录。//os.Getwd()只能获取当前项目的工作目录,并不是当前文件所在路径path, _ := os.Getwd()fmt.Println("Path:", path)err := os.Chdir("F:\\goworks\\src\\jingtian\\yufa\\错误与异常")if err != nil {return}//再次查看路径path2, _ := os.Getwd()fmt.Println("再次查看Path:", path2)//打开一个文件 os 系统包,所有可以用鼠标和键盘能执行的事件,都可以用程序实现//os.Open()返回 一个文件对象和错误error// func Open(name string) (*File, error)file, err2 := os.Open("aaa.txt")// 在开发中,我们需要思考这个错误的类型  PathError// 1、文件不存在 err// 2、文件被占用 err// 3、文件被损耗 err// 调用方法后,出现错误,需要解决if err2 != nil {fmt.Println(err2)return}fmt.Println(file.Name())
}// 在实际工程项目中,
// 我们希望通过程序的错误信息快速定位问题,但是又不喜欢错误处理代码写的冗余而又啰嗦。
// Go语言没有提供像Java. c#语言中的try...catch异常处理方式,
// 而是通过函数返回值逐层往上抛, 如果没有人处理这个错误,程序就终止 panic// 这种设计,鼓励工程师在代码中显式的检查错误,而非忽略错误。
// 好处就是避免漏掉本应处理的错误。但是带来一个弊端,让代码繁琐。// Go中的错误也是一种类型。错误用内置的error类型表示。就像其他类型的,如int, float64。
// 错误值可以存储在变量中,从函数中返回,传递参数 等等。

如果文件不存在,运行就会捕获错误
在这里插入图片描述

文件存在,就可以正常打印文件名称
在这里插入图片描述

(1)自定义错误

1. 使用errors.New()

errors.New()函数是最简单的创建错误的方式。它接受一个字符串作为参数,并返回一个实现了error接口的错误值。
返回值的类型为 *errors.errorString,可以使用Error()方法,将err转化为字符串
看下源码
在这里插入图片描述

package mainimport ("errors""fmt"
)func main() {err := errors.New("这是一个错误")if err != nil {fmt.Println(err)fmt.Printf("错误类型%T\n", err)//可以使用Error()方法,将err转化为字符串// 注意,如果err为空,调用Error()方法会报错,所以该方法一定要在if err != nil条件中执行fmt.Printf("错误类型%T\n", err.Error())}
}

在这里插入图片描述

2.使用fmt.Errorf()

fmt.Errorf()函数比errors.New()更灵活,它允许你使用格式化字符串来创建错误。这对于需要动态构建错误信息的场景非常有用。

package mainimport ("fmt"
)func main() {err := fmt.Errorf("错误代码: %d, 错误信息: %s", 1001, "操作失败")if err != nil {fmt.Println(err.Error())}
}

在这里插入图片描述

3. 综合案例
package mainimport ("errors""fmt"
)// 自己定义一个错误
// 1、errors.New("xxxxx")
// 2、fmt.Errorf()
// 都会返回  error 对象, 本身也是一个类型func main() {//根据用户传参数据,用我们定义好的函数处理age_err := setAge(-3)if age_err != nil {fmt.Println(age_err)}fmt.Printf("%T\n", age_err) // *errors.errorString//如果age_err为空,调用Error()方法会报错fmt.Printf("%T\n", age_err.Error()) // string// 方式二errInfo1 := fmt.Errorf("我是一个错误信息:%d\n", 500)//errInfo2 := fmt.Errorf("我是一个错误信息:%d\n", 404)if errInfo1 != nil {// 处理这个错误fmt.Println(errInfo1)fmt.Printf("%T\n", errInfo1.Error())}}// 设置年龄的函数,一定需要处理一些非正常用户的请求
// 返回值为 error 类型  这个是内置类型
// 作为一个开发需要不断思考的事情,代码的健壮性和安全性
func setAge(age int) error {if age < 0 {// 给出一个默认值age = 3// 抛出一个错误 errors 包return errors.New("年龄不合法")}// 程序正常的结果,给这个用户赋值fmt.Println("年龄设置成功:age=", age)//年龄合法,就返回nilreturn nil
}

在这里插入图片描述

(2)自定义错误类型(难点)

虽然errors.New()和fmt.Errorf()很方便,但在某些情况下,你可能需要更丰富的错误信息。这时,可以通过自定义类型来实现go内置的error接口。
自定义错误类型步骤

1、定义一个结构体
// JingTian 定义一个结构体
type JingTian struct {msg  stringcode int
}
2、为该结构体创建个方法,实现go内置error接口中的Error方法

内置接口
在这里插入图片描述

// 注意,Error()方法开头大写 string
// 实现内置error接口的Error方法
// 注意,方法的调用者用指针类型,因为结构体是值类型,不同函数里面的操作是互相独立的
func (e *JingTian) Error() string {//  fmt.Sprintf() 返回stringreturn fmt.Sprintf("错误信息:%s,错误代码:%d\n", e.msg, e.code)
}
3、创建个方法测试
// 使用错误测试
func test(i int) (int, error) {// 需要编写的错误if i != 0 {//自带的 errors.New()和fmt.Errorf() 只能返回字符串类型的错误信息,不常用,信息太少了// 更多的时候我们会使用自定义类型的错误//注意,返回的错误用内存地址,因为结构体是值类型return i, &JingTian{msg: "非预期数据", code: 500}}// 正常结果return i, nil
}
4、main方法中写逻辑
func main() {i, err := test(1)if err != nil {fmt.Println(err)//查看错误类型fmt.Printf("%T\n", err)ks_err, ok := err.(*JingTian)if ok {if ks_err.print() {// 处理这个错误中的子错误的逻辑}fmt.Println(ks_err.msg)fmt.Println(ks_err.code)}}fmt.Println(i)}

完整代码

package mainimport ("fmt"
)// JingTian 定义一个结构体
type JingTian struct {msg  stringcode int
}// 注意,Error()方法开头大写 string
// 实现内置error接口的Error方法
// 注意,方法的调用者用指针类型,因为结构体是值类型,不同函数里面的操作是互相独立的
func (e *JingTian) Error() string {//  fmt.Sprintf() 返回stringreturn fmt.Sprintf("错误信息:%s,错误代码:%d\n", e.msg, e.code)
}// 自定义错误,里面还可以写一些方法
// 处理error的逻辑
func (e *JingTian) print() bool {fmt.Println("hello,world")return true
}// 使用错误测试
func test(i int) (int, error) {// 需要编写的错误if i != 0 {//自带的 errors.New()和fmt.Errorf() 只能返回字符串类型的错误信息,不常用,信息太少了// 更多的时候我们会使用自定义类型的错误//注意,返回的错误用内存地址,因为结构体是值类型return i, &JingTian{msg: "非预期数据", code: 500}}// 正常结果return i, nil
}func main() {i, err := test(1)if err != nil {fmt.Println(err)//查看错误类型fmt.Printf("%T\n", err)ks_err, ok := err.(*JingTian)if ok {if ks_err.print() {// 处理这个错误中的子错误的逻辑}fmt.Println(ks_err.msg)fmt.Println(ks_err.code)}}fmt.Println(i)}

在这里插入图片描述

go语言中,业务逻辑其实代码量并不大,大多数是在处理错误逻辑
比如下购物商城代码:
购物

下单:

1、查询商品信息 (FindGoodsError: msg、code | fun-商品不在了 ,fun-商品失效 ,fun-网络错误 )

2、查询库存 (FindxxxError: msg、code | fun-库存为0 ,fun-库存>0)

3、查询物流是否可以到达 (xxxError: msg、code | fun ,fun)

4、查询价格生成订单 (xxxError: msg、code | fun ,fun)

5、支付成功与否 (xxxError: msg、code | fun ,fun)

6、成功就产生一个订单,推送到商家和物流 (xxxError: msg、code | fun ,fun)

2. Go语言的异常处理机制

panic 和 recover
与错误处理不同,Go语言中的异常处理是通过panic和recover关键字来实现的。panic用于表示程序中的严重错误,它会导致程序中断执行;recover用于捕获panic,并恢复程序的正常执行流程。

(1)使用panic

什么时候会发生恐慌panic,我们不知道什么时候会报错
程序运行的时候会发生panic
手动抛出panic。我们在一些能够预知到危险的情况下,可以主动抛出
panic可以接受任何类型的值作为参数,通常是一个字符串或错误对象,用于描述发生的异常。
使用 panic() 程序就会终止,停在这里强制结束

看下源码
在这里插入图片描述

package mainimport "fmt"func main() {panic("发生了异常")//panic后面的代码,程序不会执行fmt.Println("hello world")
}

在这里插入图片描述

在上面的例子中,程序会在执行到panic时中断,并打印出"发生了异常"这条消息。

如果有panic发生,我们尽可能接收它,并处理
出现了panic之后,如果panic语句前面有defer语句,先执行所有的defer语句。panic语句后面的defer语句不再执行

package mainimport "fmt"// panic  recover
//
// 出现了panic之后,如果panic语句前面有defer语句,先执行所有的defer语句。
//
// defer : 延迟函数,倒序执行,处理一些问题。
func main() {defer fmt.Println("main--1")defer fmt.Println("main--2")fmt.Println("main--3")testPanic(1) // 外部函数,执行完panic之前的所有defer//后面的都不执行了defer fmt.Println("main--4")fmt.Println("main--5")
}
func testPanic(num int) {defer fmt.Println("testPanic--1")defer fmt.Println("testPanic--2")fmt.Println("testPanic--3")// 如果在函数中一旦触发了 panic,会终止后面要执行的代码。// 如果panic语句前面存在defer,正常按照defer逻辑执行。panic语句后面的defer语句不再执行if num == 1 {panic("出现预定的异常----panic")}defer fmt.Println("testPanic--4")fmt.Println("testPanic--5")
}

在这里插入图片描述

(2)使用recover

go 语言是追求简洁的,他没有使用 try…catch 语句
如果有些情况,必须要处理异常,就需要使用panic,抛出了异常,recover,接收这个异常来处理。
recover结合defer处理 panic 恐慌
recover必须在defer语句中调用,才能捕获到panic。defer语句会延迟函数的执行,直到包含它的函数即将返回时,才执行defer语句中的函数。
一般我们在某个函数抛出的panic,就在那个函数里面解决了
recover会返回panic的参数

recover返回任意类型
在这里插入图片描述

1. recover案例展示
package mainimport ("fmt"
)func main() {//defer语句绑定的匿名函数defer func() {r := recover()if r != nil {fmt.Println("捕获到异常:", r)}}()panic("发生了异常")fmt.Println("这行代码不会被执行")
}

在这里插入图片描述

在这个例子中,尽管在defer之后有panic调用,但defer中的函数仍然会执行,并捕获到panic抛出的异常。然后,程序会跳过panic之后的代码,继续执行defer之后的逻辑。

2. recover结合多个defer执行顺序
package mainimport "fmt"// panic  recover
//
// 出现了panic之后,如果有defer语句,先执行所有的defer语句。
//
// defer : 延迟函数,倒序执行,处理一些问题。
func main() {defer fmt.Println("main--1")defer fmt.Println("main--2")fmt.Println("main--3")testPanic2(1) // 外部函数,如果在函数内部已经处理panic,那么程序会继续执行defer fmt.Println("main--4")fmt.Println("main--5")
}
func testPanic2(num int) {// 出去函数的时候处理这里面可能发生的panic// recover func recover() any 返回panic传递的值// panic   func panic(v any)defer func() {if msg := recover(); msg != nil {fmt.Println("recover执行了... panic msg:", msg)// 处理逻辑fmt.Println("---------程序已恢复----------")}}()defer fmt.Println("testPanic--1")defer fmt.Println("testPanic--2")fmt.Println("testPanic--3")// 如果在函数中一旦触发了 panic,会终止后面要执行的代码。// 如果存在defer,正常按照defer逻辑执行if num == 1 {panic("出现预定的异常----panic")}defer fmt.Println("testPanic--4")fmt.Println("testPanic--5")
}

在这里插入图片描述

执行逻辑:

1、panic 触发

2、触发panic当前函数panic前面的所有defer语句,倒序执行

3、直到遇到recover处理了这个panic…函数结束

4、main,继续向下执行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/437049.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯—STM32G431RBT6(IIC通信--EEPROM(AT24C02)存储器进行通信)

一、什么是IIC&#xff1f;24C02存储器有什么用&#xff1f; IIC &#xff08;IIC 是半双工通信总线。半双工意味着数据在某一时刻只能沿一个方向传输&#xff0c;即发送数据的时候不能接收数据&#xff0c;接收数据的时候不能发送数据&#xff09;即集成电路总线&#xff08;…

AI智能时代的图书馆未来,你想象过吗!

AI智能时代的图书馆未来&#xff0c;你想象过吗&#xff01; 前言AI智能时代的图书馆未来 前言 教育数字化和 AI 时代的浪潮正汹涌而来&#xff0c;图书馆也站在了变革的十字路口。我们看到高等教育正在发生深刻的变革&#xff0c;从教学模式到人才培养理念&#xff0c;都在经…

Linux 再入门整理:详解 /etc/fstab 文件

目录 1. 什么是 /etc/fstab2. /etc/fstab 文件的格式2.1 设备文件 (Device)2.2 挂载点 (Mount Point)2.3 文件系统类型 (File System Type)2.4 挂载选项 (Mount Options)2.5 Backup Operation&#xff08;dump 参数&#xff09;2.6 Pass Order (fsck 参数)2.6.1 参数设置2.6.2 …

智慧防灾,科技先行:EasyCVR平台助力地质灾害视频监测系统建设

随着科技的飞速发展&#xff0c;视频监控技术已成为地质灾害监测与预警的重要手段之一。在众多视频监控平台中&#xff0c;EasyCVR视频汇聚平台凭借其强大的视频整合、实时传输、视频处理及分发等能力&#xff0c;在地质灾害场景中展现出显著的应用优势。 一、实时监测与远程监…

【RabbitMQ——具体使用场景】

1. 异步 1.1 同步异步的问题&#xff08;串行&#xff09; 串行方式&#xff1a;将订单信息写入数据库成功后&#xff0c;发送注册邮件&#xff0c;再发送注册短信。以上三个任务全部完成后&#xff0c;返回给客户端 public void makeOrder(){// 1 :保存订单 orderService.…

SpringBoot上传图片实现本地存储以及实现直接上传阿里云OSS

一、本地上传 概念&#xff1a;将前端上传的文件保存到自己的电脑 作用&#xff1a;前端上传的文件到后端&#xff0c;后端存储的是一个临时文件&#xff0c;方法执行完毕会消失&#xff0c;把临时文件存储到本地硬盘中。 1、导入文件上传的依赖 <dependency><grou…

[uni-app]小兔鲜-04推荐+分类+详情

热门推荐 新建热门推荐组件, 动态设置组件的标题 <template><!-- 推荐专区 --><view class"panel hot"><view class"item" v-for"item in list" :key"item.id">... ...<navigator hover-class"none&…

C# HttpClient请求URL重定向后丢失Authorization认证头

搜查官方文档后发现&#xff1a; HttpWebRequest.AllowAutoRedirect Property (System.Net) | Microsoft Learn 微软提供的http类库HttpClient &#xff08;HttpWebRequest\WebClient已不推荐使用&#xff0c;用HttpClient代替&#xff09;有备注提醒&#xff1a;当使用自动重…

Android Button “No speakable text present” 问题解决

记录一个问题&#xff0c;今天让同学们做了个小车控制界面&#xff0c;使用Button控件&#xff0c;删除设置的text属性&#xff0c;会出现“No speakable text present”的错误&#xff0c;如图所示。这是由于Android的无障碍设置需要朗读Button的文本&#xff0c;如果没有设置…

基于elasticsearch存储船舶历史轨迹: 使用scroll滚动技术实现大数据量搜索

文章目录 引言I 轨迹索引的设计轨迹文档定时创建索引手动添加索引并为索引添加别名POST请求批量插入文档数据II 查询文档数据基于scroll滚动技术实现大数据量搜索查询轨迹查询参数返回dtoIII 知识扩展空指针处理术语介绍基于 search_after 实现深度分页引言 需求: 存储轨迹,…

免费 Oracle 各版本 离线帮助使用和介绍

文章目录 Oracle 各版本 离线帮助使用和介绍概要在线帮助下载离线文档包&#xff1a;解压离线文档&#xff1a;访问离线文档&#xff1a;导航使用&#xff1a;目录介绍Install and Upgrade&#xff08;安装和升级&#xff09;&#xff1a;Administration&#xff08;管理&#…

大数据毕业设计选题推荐-民族服饰数据分析系统-Python数据可视化-Hive-Hadoop-Spark

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

sentinel原理源码分析系列(一)-总述

背景 微服务是目前java主流开发架构&#xff0c;微服务架构技术栈有&#xff0c;服务注册中心&#xff0c;网关&#xff0c;熔断限流&#xff0c;服务同学&#xff0c;配置中心等组件&#xff0c;其中&#xff0c;熔断限流主要3个功能特性&#xff0c;限流&#xff0c;熔断&…

[MAUI]数据绑定和MVVM:MVVM的属性验证

一、MVVM的属性验证案例 Toolkit.Mvvm框架中的ObservableValidator类,提供了属性验证功能,可以使用我们熟悉的验证特性对属性的值进行验证,并将错误属性提取和反馈给UI层。以下案例实现对UI层的姓名和年龄两个输入框,进行表单提交验证。实现效果如下所示 View<ContentP…

【Python】Django Grappelli:打造优雅且现代化的 Django 管理后台

在 Django 开发中&#xff0c;默认的 Django Admin 界面尽管功能强大且能满足大多数管理需求&#xff0c;但其界面设计相对基础&#xff0c;尤其在用户体验和视觉呈现上显得较为简约。在一些项目中&#xff0c;开发者可能需要更加现代化且美观的后台界面。这时&#xff0c;Djan…

【Redis】Redis中的 AOF(Append Only File)持久化机制

目录 1、AOF日志 2、AOF 的执行顺序与潜在风险 3、如何优化 AOF&#xff1f;&#xff08;写入策略&#xff09; 4、AOF重写机制&#xff08;防止日志文件无限增长&#xff09; 1、AOF日志 想象一下&#xff0c;Redis 每次执行写操作的时候&#xff0c;都把这些操作以追加的…

人工智能 | 手工测试用例转Web自动化测试生成

简介 在传统编写 Web 自动化测试用例的过程中&#xff0c;基本都是需要测试工程师&#xff0c;根据功能测试用例转换为自动化测试的用例。市面上自动生成 Web 或 App 自动化测试用例的产品无非也都是通过录制的方式&#xff0c;获取操作人的行为操作&#xff0c;从而记录测试用…

大语言模型入门(一)——大语言模型智能助手

一、大语言模型智能助手 2022年末ChatGPT一经推出&#xff0c;一时间不注册个账号用一下都跟不上潮流了。然而&#xff0c;我们要注册OpenAI的账号使用ChatGPT还是一件比较麻烦的事情&#xff08;懂的都懂&#xff09;。好在&#xff0c;国内各大团队非常给力地及时推出了自研的…

php 平滑重启 kill -SIGUSR2 <PID> pgrep命令查看进程号

有时候我们使用nginx 大家都知道平滑重启命令: /web/nginx/sbin/nginx -s reload 但大家对php-fpm 重启 可能就是简单暴力的kill 直接搞起了 下面介绍一个sh 文件名保存为start_php.sh 来对php-fpm 进行平滑重启 #!/bin/bash# 检查 PHP-FPM 是否运行 if ! pgrep php-…

yolov11模型在bdd100k数据集上的应用【代码+数据集+python环境+训练/应用GUI系统】

yolov8/9/10/11模型在bdd100k数据集上的应用【代码数据集python环境训练/应用GUI系统】 yolov8/9/10/11模型在bdd100k数据集上的应用【代码数据集python环境训练/应用GUI系统】 yolov8/9/10/11模型在bdd100k数据集上的应用【代码数据集python环境训练/应用GUI系统】 bdd100k数据…