Golang语言异常机制解析:错误策略与优雅处理

 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站https://www.captainbed.cn/kitie。

前言

作为开发者来说,我们没办法保证程序在运行过程中永远不会出现异常,对于异常,在很多编程语言中,可以用 try-catch语句来捕获,而Go语言的开发者显然觉得 try-catch被滥用了,因此 Go不支持使用 try-catch语句捕获异常处理。

那么,Go语言是如何定义和处理程序的异常呢?

Go语言的将程序运行出现的问题分为两种:错误(error)和异常(exception),错误是程序(比如一个函数)运行的预期结果之一,当你调用一个函数时,就应该处理出现错误的情况,而异常是不可预期的(当然也可以手动触发)且会导致程序中断运行的严重错误。

目录

前言

Go错误处理策略

创建error的几种方式

errors包

fmt包

自定义错误类型

如何处理错误

直接返回错误

记录日志并继续运行

记录日志并结束运行

Go异常处理机制

panic函数

recover函数

总结

Go错误处理策略

编写Go语言程序,一般推荐通过函数的最后一个返回值告诉调用者函数是否执行成功,可以分两种情况来讨论:

第一种情况,如果函数的执行结果只有正确与失败,那么返回值可以是 boolean类型:

func exists(key string) bool {//to check if the key is existsreturn true
}if ok := exists("test"); ok {// do something
}

第二种情况,如果要让调用者得到更详细的错误信息,显然只返回一个布尔值是不够的,这时候可以返回一个 error类型,error类型是一个接口,只有一个 Error方法的接口:

type error interface {Error() string
}

通过 error类型的 Error方法,可以获得更详细的错误信息,方便调用者做进一步的处理,因此在 Go标准库的方法和函数中,一般都会将 error类型作为最后一个返回值,比如我们以前文章中讲到的 os包下的 Open和 Create函数:

package osfunc Open(name string) (*File, error) {return OpenFile(name, O_RDONLY, 0)
}func Create(name string) (*File, error) {return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
}

当函数最后一个返回值 error不为 nil时,表示执行不成功,此时其他的返回值就应该忽略:

file,err := os.Open("./my.dat")if err != nil{return err
}defer file.Close()

上面代码中,如果 error不为 nil,那么变量 file则为 nil,表示无法获得一个文件句柄,这时候直接返回错误,因为如果再继续往下执行,可能会引发程序崩溃。

当然并不是所有情况下一遇到返回的 error不为 nil,就要抛弃其他返回值,比如使用 Read()方法读取文件时:

Read(p []byte) (n int, err error)

在读取文件到结尾时 Read方法会返回一个 io.EOF的错误:

var EOF = errors.New("EOF")

此时虽然 error不为 nil,但仍然应该把读取到的字节数组保存,而不是抛弃掉。

创建error的几种方式

当我们开发自己的函数时,也可以创建自己的错误类型,有以下几种方式:

errors包

errors包下的 New()函数可以创建一个只有文本信息的 error类型:

package mainfunc main() {var s = []int{1, 2, 3}s[3] = 10
}
fmt包

fmt包下的 Errorf函数可以将文本格式后作为error类型的错误信息,并返回一个error类型,因此其作用与errors.New函数类似

func getFile(name string)(*os.file,error){if name == ""{return nil,fmt.Errorf("file name could not be empty")}
}

fmt.Errorf函数还能封装其他 error类型,再返回一个新的 error类型,以此形成一条完整的错误链条:

doc, err := html.Parse(resp.Body)
resp.Body.Close()
if err != nil {return nil, fmt.Errorf("parsing %s as HTML: %v", url,err)
}
自定义错误类型

其实,上面两种创建错误类型的方式,本质上都是实现 error接口,我们也可以创建一个拥有 Error方法的类型来实现 error接口:

type Result struct {Code    intMessage stringData    interface{}
}func (r Result) Error() string {return r.Message
}

如何处理错误

当调用的函数或方法的返回值有 error类型时,最简单的当然可以选择直接忽略错误,不过更恰当的方式是处理对应的错误,有以下几种处理策略:

直接返回错误

对于函数来说,如果在执行时遇到错误,可以直接返回给上层调用者:

func SendMessage(url string) error {if url == ""{return errors.New("url can't not be empty")}_, err := http.Get(url)if err != nil {return err}return nil
}
记录日志并继续运行

当调用函数时遇到返回的错误,如果不影响程序运行,也可以选择记录错误日志并往下执行:

if err := SendMessage("https://xxx/sendMessage");err != nil{log.Printf("the message sending been broken by : %v\n", err)
}
记录日志并结束运行

如果错误影响程序的执行,也可以记录日志后,退出程序执行:

if err := SendMessage("https://xxx/sendMessage");err != nil{log.Printf("the message sending been broken by : %v\n", err)os.Exit(1)
}

记录日志并退出执行,直接用 log包的 Fatalf函数就可以做到,因此上面代码的更简洁做法是:

if err := SendMessage("https://xxx/sendMessage");err != nil{log.Fatalf("the message sending been broken by : %v\n", err)
}

Go异常处理机制

在Go语言中,异常是指会引发程序崩溃无法继续运行的错误,比如数组越界或者空指针引用等情况,这时候会触发 panic异常:

package mainfunc main() {var s = []int{1, 2, 3}s[3] = 10
}

上面程序运行结果如下,可以看出触发了数组越界的异常:

panic: runtime error: index out of range [3] with length 3

无论是在主协程还是子协程中,一旦触发 panic异常,整个程序都会终止运行。

panic函数

除了数组越界等不可预测的异常会自动触发 panic,也可以手动调用 panic函数触发异常来终止程序的运行:

func loadConfig(path string){panic("can't load the config file on path " + path)
}

一个良好的程序最好不要主动调用 panic函数,尤其是开发类库的时候,最好通过返回 error类型来告诉调用者发生了什么错误,而不是触发 panic导致程序终止运行。

recover函数

当发生 panic异常时,如果不捕获得异常,那么程序就是终止运行,在Go语言中,可以用 defer语句和 recover函数的模式来捕获 panic异常:

package mainimport ("fmt""log"
)func main() {n1 := FindElementByIndex(1)fmt.Println(n1)n2 := FindElementByIndex(4)fmt.Println(n2)
}func FindElementByIndex(index int) int {defer func() {if e := recover(); e != nil {log.Fatal(e)}}()s := []int{1, 2, 3, 4}return s[index]
}

总结

        本文深入探讨了Go语言的错误策略与异常机制。主要介绍了错误处理的重要性,以及Go语言中的错误类型和处理函数。此外还讨论了Go语言的异常机制,包括panic和recover函数的使用。通过合理的错误处理和异常处理,我们可以提高代码的可维护性和可靠性,减少潜在的bug和故障。希望本文对您有帮助,感谢阅读~

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

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

相关文章

Maven:Dmaven.multiModuleProjectDirectory system propery is not set.

eclipse中使用maven插件的时候,运行run as maven build的时候报错 -Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable and mvn script match. 直接的解决方法:使用低版本的maven 可以设一个环境变量…

分布式搜索引擎_学习笔记_2

分布式搜索引擎_学习笔记_2 在昨天的学习中,我们已经导入了大量数据到elasticsearch中,实现了elasticsearch的数据存储功能。但elasticsearch最擅长的还是搜索和数据分析。 所以今天,我们研究下elasticsearch的数据搜索功能。我们会分别使用…

Vue.js 中子组件向父组件传值的方法

Vue.js 是一款流行的 JavaScript 前端框架,它提供了一套完整的工具和 API,使得开发者可以更加高效地构建交互式的 Web 应用程序。其中,组件化是 Vue.js 的一个核心概念,通过组件化可以将一个复杂的应用程序拆分成多个独立的部分&a…

系统架构设计师考试大纲2023

一、 考试方式(机考) 考试采取科目连考、 分批次考试的方式, 连考的第一个科目作答结束交卷完成后自动进 入第二个科目, 第一个科目节余的时长可为第二个科目使用。 高级资格: 综合知识科目考试时长 150 分钟&#xff…

基于ecal的foxglove studio可视化工具的使用

ecal通讯在自动驾驶和机器人中的应用越来越多,在调试测试过程中,可以使用ecal monitor,ecal recoder和ecal player等工具,对ecal 消息进行监测录制回播。但是,有时候需要对消息进行可视化查看,比如雷达点云信息,相机图像等,可以使用foxglove studio可视化工具。 Foxg…

CSRF靶场练习

简述:CSRF漏洞实际很少;条件限制很多;局限性很大;实验仅供参考,熟悉csrf概念和攻击原理即可 Pikachu靶场 CSRF GET 登录用户vince的账户可以看到用户的相关信息; 点击修改个人信息,发现数据包…

轻量式RPC调用日志链路设计方案

导语: 调用链跟踪系统,又称为tracing,是微服务设计架构中,从系统层面对整体的monitoring和profiling的一种技术手 背景说明 由于我们的项目是微服务方向,中后台服务调用链路过深,追踪路径过长,其中某个服务报错或者异…

【Redis】实现购物秒杀及分布式锁

Redis实现购物秒杀及分布式锁 全局唯一ID Redis自增ID策略 ID构造是:时间戳 + 计数器 每天一个key,方便统计订单量 业务实现 获取指定时间的秒数 LocalDateTime timeBegin = LocalDateTime.of(2024, 1, 1, 0, 0, 0); long second = timeBegin.toEpochSecond(ZoneOffset…

Java面试题宝典(万字长文)

Java 基础 1. JDK 和 JRE 有什么区别? JRE是Java运行环境,即(Java Runtime Environment),也就是Java平台。所有的Java程序都要在JRE下才能运行。 JDK是开发工具包,即(Java Development Kit&am…

【Docker与微服务】基础篇

1 Docker简介 1.1 docker是什么 1.1.1 问题:为什么会有docker出现? 假定您在开发一个项目,您使用的是一台笔记本电脑而且您的开发环境具有特定的配置。其他开发人员身处的环境配置也各有不同。您正在开发的应用依赖于您当前的配置且还要依…

android 自定义下拉框

一、 简介: 原生Android 提供的spinner下拉框不怎么方便,样式有点丑。修改起来麻烦,于是就自己动手写了一下拉列表。 实现原理使用的是,popwindow弹框,可实现宽高自定义,下拉列表使用listview. 二、pop弹框…

大模型基础架构的变革:剖析Transformer的挑战者(中)

上一篇文章中,我们介绍了RetNet、RWKV、Mamba等有可能会替代Transformer的模型架构,这一篇文章我们将要介绍另外三个有可能会替代Transformer的模型架构,它们分别是UniRepLKNet、StripedHyena、PanGu-π,想了解之前的内容&#xf…

vue项目改造服务端渲染

vue项目改造服务端渲染 概述 【定义】 服务器渲染的Vue应用程序被认为是"同构"或"通用",因为应用程序的大部分代码都可以在服务器和客户端上运行 【优点】 与传统SPA相比,服务器端渲染(SSR)的优势主要在于: 1、更好的…

二叉树-堆应用(1)

目录 堆排序 整体思路 代码实现 Q1建大堆/小堆 Q2数据个数和下标 TopK问题 整体思路 代码实现 Q1造数据CreateData Q2建大堆/小堆 建堆的两种方法这里会用到前面的向上/向下调整/交换函数。向上调整&向下调整算法-CSDN博客 堆排序 整体思路 建堆(直…

Qt 5.9.4 转 Qt 6.6.1 遇到的问题总结(三)

1.QSet: toList 中的toList 函数已不存在,遇到xx->toList改成直接用,如下: 2.开源QWT 图形库中QwtDial中的 setPenWidth 变成 setPenWidthF函数。 3.QDateTime 中无setTime_t 改为了setSecsSinceEpoch函数。 4.QRegExp 类已不存在 可以用Q…

【定位·HTML】

定位布局可以分为以下四种: 静态定位(inherit) 相对定位(relative) 绝对定位(absolute) 固定定位(fixed) 一般的标签元素不加任何定位属性时,默认都属于静态…

百川终入海 ,一站式海量数据迁移工具 X2Doris 正式发布

在大数据分析领域,Apache Doris 作为广受认可的开源实时数据仓库,已经在越来越多行业用户的真实业务场景中得到广泛应用,成为许多企业数据分析基础设施的重要基座。尤其在过去一年多的时间里,越来越多企业选择基于 Apache Doris 进…

node.js(nest.js控制器)学习笔记

nest.js控制器: 控制器负责处理传入请求并向客户端返回响应。 为了创建基本控制器,我们使用类和装饰器。装饰器将类与所需的元数据相关联,并使 Nest 能够创建路由映射(将请求绑定到相应的控制器)。 1.获取get请求传参…

牛客——中位数图(连续子数组和二维前缀和)

链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 题目描述 给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。 输入描述: 第一行为两个正…

CentOS gui 图形界面显示文字乱码

一、现象 CentOS(CentOS 7.5)控制台下显示中文乱码: 或者通过X11 Forwarding远程显示CentOS的图形化程序文字乱码: 二、解决方法 安装中文语言包: yum install kde-l10n-Chinese 注:网上有些文章会推荐安…