一文教你如何优雅处理Golang中的异常
作者:阿拉懒神灯 发布时间:2024-02-13 21:32:33
我们在使用Golang时,不可避免会遇到异常情况的处理,与Java、Python等语言不同的是,Go中并没有try...catch...这样的语句块,我们知道在Java中使用try...catch...这种模式不仅能分离的错误与返回值和参数,也提供了结构化处理异常的可能,通过面向对象的思想,我们可以自定义错误类、子类,它们又可以包装其他错误,确保错误上下文不会丢失。但是在Go中,异常是作为函数返回值,返回给调用方的,这个时候我们如何才能更好的处理异常呢?
对于异常的处理,我们应该把握三个原则:
不重复处理异常;
异常信息中需要包含完整调用栈;
要提供异常的上下文信息;
func read(filePath string) (string, error) {
content ,err := ioutil.ReadFile(filePath)
if err != nil {
log.Printf("Read file err: %v", err)
return "", err
}
return string(content), nil
}
func parse(content string) (Employ, error) {
// 解析文件得到Employ对象
}
func checkAttr(attr interface{}) error {
// 校验对象属性
}
func commitEmployInfoFromFile(filePath string) error {
content, err := read(filePath)
if err != nil {
return errors.New("Read object file error")
}
employ, err := parse(content)
if err != nil {
return errors.New("Parse object content error")
}
if err = checkAttr(employ.Name); err != nil {
return err
}
if err = checkAttr(employ.Age); err != nil {
return err
}
if err = checkAttr(employ.Salary); err != nil {
return err
}
return nil
}
我们分析上面的代码,可以很明显看到read函数中违背了【不重复处理异常】的原则,虽然这里仅仅是打印,但是只要你向上抛异常,调用方很有可能再次打印,这就导致日志中存在大量重复信息,不便于分析。因为我们修改read函数:
func read(filePath string) (string, error) {
content ,err := ioutil.ReadFile(filePath)
if err != nil {
return "", err
}
return string(content), nil
}
再来看看这一部分代码,日志中仅仅打印了错误信息,但是缺少错误堆栈,这样非常不利于问题代码的定位。
content, err := read(filePath)
if err != nil {
return errors.New("Read object file error")
}
employ, err := parse(content)
if err != nil {
return errors.New("Parse object content error")
}
上面的代码还有一个问题,那就是错误信息都是简单的字符串信息,缺少上下文信息,比如:
errors.New("Read object file error")
我们只能知道是文件读取出错了,但无法得知是哪个文件有问题,因此我们最好加入文件信息到日志中。改良后的代码如下:
content, err := read(filePath)
if err != nil {
return fmt.Errorf("Read object file %v error: %v", filePath, err)
}
employ, err := parse(content)
if err != nil {
return fmt.Errorf("Parse object content error: %v", err)
}
最后,我们再看看这一段代码,这种写法非常常见,很多刚使用Golang的朋友都觉得非常头痛,由于Golang中没有throw或raise机制,所以会导致代码中使用大量if对错误进行处理,非常不优雅。
if err = checkAttr(employ.Name); err != nil {
return err
}
if err = checkAttr(employ.Age); err != nil {
return err
}
if err = checkAttr(employ.Salary); err != nil {
return err
}
对于这类代码我们可以使用匿名函数进行简化,我们将checkAttr和err的判断封装在匿名函数check中,一旦某一次check出现error,则都不会在进行后续的属性校验。
check := func(attr interface{}){
if err != nil{
return
}
err = checkAttr(attr)
}
check(employ.Name)
check(employ.Age)
check(employ.Salary)
return err
当然,这种方式是还需要创建一个匿名函数以及一个error变量,这会让我们的commitEmployInfoFromFile函数显得不太干净,我们可以进一步优化:
type EmployChecker struct {
err error
}
func (c *EmployChecker) check(attr interface{}) {
if c.err == nil {
c.err = checkAttr(attr)
}
}
func commitEmployInfoFromFile(filePath string) error {
content, err := read(filePath)
if err != nil {
return fmt.Errorf("Read object file %v error: %v", filePath, err)
}
employ, err := parse(content)
if err != nil {
return fmt.Errorf("Parse object content error: %v", err)
}
checker := EmployChecker{}
checker.check(employ.Name)
checker.check(employ.Age)
checker.check(employ.Salary)
err = checker.err
return err
}
当然,这种方式是有一定局限性的,它只能在对于同一个业务对象的不断操作下可以简化错误处理,对于多个业务对象的话,还是得需要各种 if err != nil
的方式。
其实,对于Go的异常处理,我们不能说Golang不支持try catch,那它就不行,君不见try catch嵌套有多可怕,我们没必要一味追求代码的简洁,从而使用各种技巧去“优化”它,只要代码不冗余,清晰,简单就可以了。
来源:https://www.cnblogs.com/alalazy/p/16849272.html


猜你喜欢
- 最近试用mysql proxy,遇到若干问题,好在一一找到了解决方案,列出来备忘。这次使用的版本是0.6.x,也许新版本就没有这些问题了。无
- if语句用来表示某种可能的情况,并如何处理该情况。if语句可以用来表示一种可能性、两种可能性或者多种可能性。1 一种可能性单个的if语句表示
- 做设计的时候,如何配色是经常让人头痛的问题,尽管很多时候,很多人都说对于色彩的掌握更多的是靠感觉,但是不得不说,感觉也是要有依据的。所以颜色
- Go语言集成开发环境之VS Code安装使用VS Code是微软开源的一款编辑器,插件系统十分的丰富。下面介绍如何用VS Code搭建go语
- 1.将下面一段代码插入<head>与</head>之间:<script> function&
- 简介一款跨平台/无依赖的自动化测试工具,目测只能控制鼠标/键盘/获取屏幕尺寸/弹出消息框/截屏。安装pip install pyautogu
- 覆盖原型//囚犯示例 //1.定义原型对象 var proto = { sentence : 4, //监禁年限 probation:
- pycharm每次新建项目都需要重新安装库,解决方法如下:新建项目时自定义选择库(自己安装python位置),不要创建新的(如下图)第一完成
- Rex 是 Perl 编写的基于 SSH 链接的集群配置管理系统,语法上类似 Puppet DSL。官网中文版见 http://rex.pe
- 本文实例讲述了Python实现的KMeans聚类算法。分享给大家供大家参考,具体如下:菜鸟一枚,编程初学者,最近想使用Python3实现几个
- 一、前言构建命令行程序很酷:命令行可以按照我们的设定完成相应的工作,相比 GUI 界面程序,无需花费大量时间设计 GUI 界面。但要使命令行
- 内容摘要:当我们不想让某IP服务我们的网站时,我们就要写段程序来限制IP地址。asp中如何对ip进行过滤限制?本文介绍了一种方法,这个函数只
- 分享给大家一篇文章,教你怎样用Python画了一棵圣诞树,快来学习。如何用Python画一个圣诞树呢?最简单:height = 5stars
- 中文字体设计发展到现在,风格越来越多样化,特别是在广告(美术)字体方面,因为字数少 局限小,优秀的作品层出不穷,比较突出的应用在标志设计唱片
- 现在的垃圾留言越来越智能,并且从留言内容几乎看不出来是垃圾留言,而大量的垃圾留言会导致文章可读性下降,并可能会被搜索引擎惩罚,经过一段时间的
- 大家好,我是东哥。本篇和大家介绍一个经典的异常检测算法:局部离群因子(Local Outlier Factor),简称LOF算法。背景Loc
- 1.引言热力图的想法很简单,用颜色替换数字。现在,这种可视化风格已经从最初的颜色编码表格走了很长一段路。热力图被广泛用于地理空间数据。这种图
- 1.功能简介此程序模拟用户登陆商城后购买商品操作。可实现用户登陆、商品购买、历史消费记查询、余额和消费信息更新等功能。首次登陆输入初始账户资
- 如何准确获知对方来访问的时间和URL?代码如下:logfile.asp<%Dim ValidLog '&n
- 对于更完整的代码可以参考,这个是支持数据库的版本。经过测试Asp+Ajax仿google搜索提示效果 数据库版google搜索提示.rar