前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何在 Go 中优雅的处理和返回错误(1)——函数内部的错误处理

如何在 Go 中优雅的处理和返回错误(1)——函数内部的错误处理

原创
作者头像
amc
修改于 2021-09-18 10:15:29
修改于 2021-09-18 10:15:29
9.7K0
举报
文章被收录于专栏:后台全栈之路后台全栈之路

在使用 Go 开发的后台服务中,对于错误处理,一直以来都有多种不同的方案,本文探讨并提出一种从服务内到服务外的错误传递、返回和回溯的完整方案,还请读者们一起讨论。


问题提出

在后台开发中,针对错误处理,有三个维度的问题需要解决:

  • 函数内部的错误处理: 这指的是一个函数在执行过程中遇到各种错误时的错误处理。这是一个语言级的问题
  • 函数/模块的错误信息返回: 一个函数在操作错误之后,要怎么将这个错误信息优雅地返回,方便调用方(也要优雅地)处理。这也是一个语言级的问题
  • 服务/系统的错误信息返回: 微服务/系统在处理失败时,如何返回一个友好的错误信息,依然是需要让调用方优雅地理解和处理。这是一个服务级的问题,适用于任何语言

针对这三个维度的问题,笔者准备写三篇文章一一说明。首先本文就是第一篇:函数内部的错误处理


高级语言的错误处理机制

  一个面向过程的函数,在不同的处理过程中需要 handle 不同的错误信息;一个面向对象的函数,针对一个操作所返回的不同类型的错误,有可能需要进行不同的处理。此外,在遇到错误时,也可以使用断言的方式,快速中止函数流程,大大提高代码的可读性。

  在许多高级语言中都提供了 try ... catch 的语法,函数内部可以通过这种方案,实现一个统一的错误处理逻辑。而即便是 C 这种 “中级语言”,虽然没有 try catch,但是程序员也可以使用宏定义配合 goto LABEL 的方式,来实现某种程度上的错误断言和处理。


Go 的错误断言

  在 Go 的情况就比较尴尬了。我们先来看断言,我们的目的是,仅使用一行代码就能够检查错误并终止当前函数。

由于没有 throw、没有宏,如果要实现一行断言,有两种方法。

方法一:单行 if + return

第一种是把 if 的错误判断写在一行内,比如:

代码语言:go
AI代码解释
复制
	if err != nil { return err }

这种方法有值得商榷的点:

  • 虽然符合 Go 的代码规范,但是在实操中,if 语句中的花括号不换行这一点还是非常有争议的,并且笔者在实际代码中也很少见到过
  • 代码不够直观,大致浏览代码的时候,断言代码不显眼,而且在花括号中除了 return 之外也没法别的了,原因是 Go 的规范中强烈不建议使用 ; 来分隔多条语句(if 条件判断除外)

因此,笔者强烈不建议这么做。

方法二:panic + recover

第二种方法是借用 panic 函数,结合 recover 来实现,如以下代码所示:

代码语言:go
AI代码解释
复制
func SomeProcess() (err error)
	defer func() {
		if e := recover(); e != nil {
			err = e.(error)
		}
	}()

	assert := func(cond bool, e error) {
		if !cond {
			panic(e)
		}
	}

	// ...

	err = DoSomething()
	assert(err == nil, fmt.Errorf("DoSomething() error: %w", err))

	// ...
}

  这种方法好不好呢?我们要分情况看:

  首先,panic 的设计原意,是在当程序或协程遇到严重错误,完全无法继续运行下去的时候,才会调用(比如段错误、共享资源竞争错误)。这相当于 Linux 中 FATAL 级别的错误日志,用这种机制,仅仅用来进行普通的错误处理(ERROR 级别),杀鸡用牛刀了。

  其次,panic 调用本身,相比于普通的业务逻辑的系统开销是比较大的。而错误处理这种事情,可能是常态化逻辑,频繁的 panic - recover 操作,也会大大降低系统的吞吐。

  但是话虽这么说,使用 panic 来断言的方案,虽然在业务逻辑中基本上不用,但在测试场景下则是非常常见的。测试嘛,用牛刀有何不可?稍微大一点的系统开销也没啥问题。对于 Go 来说,非常热门的单元测试框架 goconvey 就是使用 panic 机制来实现单元测试中的断言,用的人都说好。

结论建议

  综上,在 Go 中,对于业务代码,笔者不建议采用断言,遇到错误的时候建议还是老老实实采用这种格式:

代码语言:go
AI代码解释
复制
if err := DoSomething(); err != nil {
	// ...
}

  而在单测代码中,则完全可以大大方方地采用类似于 goconvey 之类基于 panic 机制的断言。

Go 的 try ... catch

  众所周知,Go(当前版本 1.17)是没有 try ... catch 的,而且从官方的态度而言,短时间内也没有明确的计划。但是程序员有这个需求呀。这里也催生出了集中解决方案

defer 函数

  笔者采用的方法,是将需要返回的 err 变量在函数内部全局化,然后结合 defer 统一处理:

代码语言:go
AI代码解释
复制
func SomeProcess() (err error) { // <-- 注意,err 变量必须在这里有定义
	defer func() {
		if err == nil {
			return
		}

		// 这下面的逻辑,就当作 catch 作用了
		if errors.Is(err, somepkg.ErrRecordNotExist) {
			err = nil		// 这里是举一个例子,有可能捕获到某些错误,对于该函数而言不算错误,因此 err = nil
		} else if errors.Like(err, somepkg.ErrConnectionClosed) {
			// ...			// 或者是说遇到连接断开的操作时,可能需要做一些重连操作之类的;甚至乎还可以在这里重连成功之后,重新拉起一次请求
		} else {
			// ...
		}
	}()

	// ...

	if err = DoSomething(); err != nil {
		return
	}

	// ...
}

  这种方案要特别注意变量作用域问题:

  比如前面的 if err = DoSomething(); err != nil { 行,如果我们将 err = ... 改为 err := ...,那么这一行中的 err 变量和函数最前面定义的 (err error) 不是同一个变量,因此即便在此处发生了错误,但是在 defer 函数中无法捕获到 err 变量了。

  在 try ... catch 方面,笔者其实没有特别好的方法来模拟,即便是上面的方法也有一个很让人头疼的问题:defer 写法导致错误处理前置,而正常逻辑后置了。

命名的错误处理函数

  要解决前文提及的 defer 写法导致错误处理前置的问题,有第一种解决方法是比较常规的,那就是将 defer 后面的匿名函数改成一个命名函数,抽象出一个专门的错误处理函数。这个时候我们可以将上一段函数进行这样的改造:

代码语言:go
AI代码解释
复制
func SomeProcess() error {
	// ...

	if err = DoSomething(); err != nil {
		return unifiedError(err)
	}

	// ...
}

func unifiedError(err error) error {
	if errors.Is(err, somepkg.ErrRecordNotExist) {
		return nil		// 有可能捕获到某些错误,对于该函数而言不算错误,因此 err = nil

	} else if errors.Like(err, somepkg.ErrConnectionClosed) {
		return fmt.Errorf("handle XXX error: %w", err)

	// ...

	} else {
		return err
	}
}

  这样就舒服一些了,至少逻辑前置,错误处理后置。不过读者肯定会发现——这不是什么语言都可以这么搞嘛?诚然,这怎么看都不像是对 try ... catch 的模拟,但这种方法依然很推荐,特别是错误处理代码很长的时候。

goto LABEL

  理论上,我们可以通过 goto 语句,将错误处理后置,比如:

代码语言:go
AI代码解释
复制
func SomeProcess() error {
	// ...

	if err = DoSomething(); err != nil {
		goto ERR
	}

	// ...

	return nil

ERR:
	// ...
}

  对 C 语言比较熟悉的同学可能会觉得很亲切,因为在 Linux 内核中就有大量这种写法。这种写法呢,笔者其实说不出具体不好的地方,但是这个看起来很像 C 的写法,其实限制很多,反而比起 C 而言,需要注意的地方也更多:

  • 仅限于 ANSI-C 的话,要求所有的局部变量都需要前置声明,这就避免了因为变量作用域而带来的同名变量覆盖;但 Go 需要注意这个问题。
  • C 支持宏定义,配合前文可以实现断言,使得错误处理语句可以做得比较优雅;而 Go 不支持
  • Go 经常有很多匿名函数,匿名函数无法 goto 到外层函数的标签,这也限制了 goto 的使用

  不过笔者倒也不是不支持使用 goto,只是觉得在现有机制下,还是使用前两种模式比较符合 Go 的习惯。


  下一篇文章是《如何在 Go 中优雅的处理和返回错误(2)——函数/模块的错误信息返回》,笔者详细整理了 Go 1.13 之后的 error wrapping 功能,敬请期待~~


本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

原作者: amc,欢迎转载,但请注明出处。

原文标题:《如何在 Go 中优雅的处理和返回错误(1)——函数内部的错误处理

发布日期:2021-09-18

原文链接:https://cloud.tencent.com/developer/article/1879728

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
停课不停学浪潮下,线下教育机构如何转型线上,突出疫情重围
2020年伊始,一场突如其来的新冠肺炎疫情给教育行业的线下培训带来“迎头痛击”,受冲击的程度如何,我们可以从教育部、各级教育厅和教育局的应对策略中得到基本解答:
盈鱼MA
2020/02/25
9310
停课不停学浪潮下,线下教育机构如何转型线上,突出疫情重围
教学直播系统的应用场景和变现模式详解
随着国内疫情逐渐缓解,各行各业都在迅速复苏。在这期间受冲击最大的,应该是教育机构。其中,大大小小的线下中小型机构普遍遭遇了收入断崖式减少、老客户退费流失、未来经营模式不明确的情况,而线上教培机构凭借自身的各类教学直播系统,顺势而上,趁此机会将直播授课、知识付费、网校建设等模式发挥到极致。那么,对于线下教培机构,他们未来必定会遭遇转型的选择,趁此机会,小编就为大家讲解下,教学直播系统有哪些应用场景,如何实现,以及目前的变现模式都有哪些?
万岳教育系统
2020/03/30
1.2K0
教学直播系统的应用场景和变现模式详解
「企业级产品设计」B 端教育产品的情感化设计(交互篇)
B 端产品设计如何兼顾产品工具属性与情感化体验?如何通过设计让枯燥的学习过程变得有趣,把 “要我学” 变成 “我要学”,提升学员学习积极性?本文将通过我们在 B 端教育产品 「学习科学师训平台」小程序的设计经验,讲一讲如何做 B端教育产品的情感化设计。 一个教师的执教生涯中可能会经历上百次的教师培训,大到国家级培训、市级培训,小到区级培训、学校培训,既有线下集中培训,也有线上网课。国家为此投入了大量的人力物力财力,但由于部分网络培训课形式主义严重、教师培训内容“假大空”等原因,导致教师可能对培训有抵触心理
腾讯云设计中心
2022/05/05
7600
「企业级产品设计」B 端教育产品的情感化设计(交互篇)
在线培训、在线健身、在线学一切!行业新模式激发双赢新可能
与传统的线下模式相比,线上化能够带来更灵活优质的体验、更低成本的交付、更广范围的覆盖,但很多行业的线上化探索因为开发周期长、门槛高、功能繁复等原因,并不顺利。而腾讯云音视频多人会议组件(TUIRoomKit)这个数字化新工具,则让音乐教学、美术培训、健身团课、考证考研、教学研讨、讲座论坛、企业培训这些原先定位线下的生意,终于能够统统搬到线上。而且这个“搬家列表”还在持续壮大,越来越多的行业正在利用腾讯云音视频多人会议组件(TUIRoomKit)激发自身业务的双赢新可能。
腾讯云音视频
2024/12/19
1320
在线培训、在线健身、在线学一切!行业新模式激发双赢新可能
小型教育网站的开发与建设-前言与需求分析(二)
在互联网快速发展的时代,线上教育越来越被重视,线下的教育在传授学生知识的过程中会受到时间,空间等各方面的限制,所以我开发一个在线教育平台,给大家提供一个网上学习的机会。通过这个平台,可以为学生提供大量优质的教育课程,大幅度减少线下学习的开支,同时可以随时打开视频学习。
jiankang666
2022/05/12
6930
小型教育网站的开发与建设-前言与需求分析(二)
2022年教培行业研究报告
教育培训及相关产业是指国家学校教育制度系统和非学制系统有计划、有组织地为社会公众提供各种教育培训及相关产品(货物和服务)的生产活动集合。
资产信息网
2022/03/23
1.1K0
2022年教培行业研究报告
在线教育技术方案,究竟哪种好?
这一次疫情给整个教育行业带来了巨大的影响,在线教育量流量迎来了爆发式增长,成为了当前的热点话题,与此同时传统的线下教育机构也面临着巨大的生存挑战。
腾讯云开发者
2020/04/07
8.7K0
腾讯教育杨晖:“精细化分工+AI技术”将引领下一次在线教育变革
10月10日,2020中国民办教育校长联合大会在南京召开,大会旨在搭建全球教育产业链共享服务融平台,以务实中国教育者需求为核心,与万千教育者共成长。大会现场,腾讯教育副总经理杨晖发表《进击的在线教育》主题演讲,与在座教育同行探讨教培行业的过去、当下与未来。杨晖认为,在线教育行业目前正处在高速增长阶段,但尚未达到理想状态,随着5G与AI技术力量的发展,“优秀师资精细化分工与智能技术”的结合将带来教学模式迭代,引领下一次在线教育变革,而在线教育也将在5年内快速进入成熟阶段。 据杨晖介绍,腾讯教育的业务布局
鹅老师
2020/10/14
5620
腾讯教育陈书俊:超大班、小班制、混合式 腾讯课堂三大在线教学模式助力“停课不停学”
3月14-15日,由北京师范大学未来教育高精尖创新中心和腾讯教育携手主办的“未来在线教育云端论坛”正式启动。全国顶级教育专家、知名校长与企业精英通过腾讯云大学、腾讯会议两大平台相聚“云端”,采用直播互动的方式,与全国教育工作者一起,深入探讨如何基于互联网开展更加高效、有价值的在线教育教学活动,以及未来教育教学的形态。 作为主办方代表之一,腾讯教育副总裁、腾讯在线教育部总经理陈书俊出席论坛并发表演讲。陈书俊讲述了腾讯课堂产品平台升级历程:从专为疫情定制开发10秒就能开课的“老师极速版”到不断迭代更新并适
鹅老师
2020/06/10
1.2K0
在线直播教育系统的互动功能有何特点
自在线直播教育系统诞生的那天起,关于它的互动功能就没有停止过讨论。对于这一点,特别是对在线教育模式不怎么熟悉的人员,亦或是想要从线下转到线上的教培机构,一直存在着质疑。的确,不论是从授课形式上来讲,还是从功能上来讲,在线直播教育系统的互动功能既有优点,也有缺点,今天我们就来详细介绍下,它的互动功能究竟有何特点。
万岳教育系统
2020/05/18
1.8K0
在线直播教育系统的互动功能有何特点
如何设计好一门集成电路设计MOOC课程
在过去的一年中,我发布了两门在线MOOC课程,分别是中国大学MOOC平台的“芯动力——硬件加速设计方法”、IC创新学院的“数字集成电路静态时序分析基础”均收到了较好的反馈。
网络交换FPGA
2020/09/28
1.1K0
武汉java公司排名_武汉十大it培训机构
说起Java大家一定不陌生,毕竟Java这几年通过互联网+理念慢慢的渗透到了各大行业中,现在的Java软件开发岗位尤为火爆。同时也吸引着不少年轻人选择通过Java培训加入到行业中,在武汉,Java培训机构也是不少,想要在其中选择一家适合自己的是不太简单的,在这里,排名榜小编作为一名IT行业的观察者,从课程设计、教师资质、就业等多方面对武汉Java培训机构进行了一系列的考察和筛选,得到了如下武汉Java培训机构排名榜单,排名结果仅供大家参考:
全栈程序员站长
2022/11/09
1.9K0
武汉java公司排名_武汉十大it培训机构
OMO时代 教育企业最重要的是在线课堂能力和营销获客能力
新冠疫情的爆发,对教育行业造成了巨大的影响,无论是线下还是线上教育机构,都经历了前所未有的冲击与变革。而进入后疫情时代,教育企业又该如何顺势而变,积极应对行业新机遇与挑战? 7月31日,由腾讯教育菁锐俱乐部举办的“疫情常态化下的教育企业OMO转型”主题沙龙在上海开幕。本次沙龙邀请了来自好未来、Tutor ABC、精锐教育、优学堂等众多国内一线教育企业的嘉宾代表,共同探讨教育OMO变革之路。腾讯云副总裁、腾讯教育副总裁付曼青,腾讯云副总裁、腾讯教育副总裁王帅以及腾讯教育相关业务负责人也出席本
鹅老师
2020/08/04
7690
K12教育江湖的班课模式之争
作为刚需领域,K12教育历来是机构必争之地。而在黑天鹅频发的情况下,主流的教育模式之间,为争夺生源而相互攻击的事情也愈演愈烈。比如,大班课机构会说小班课、1对1没名师,小班课则会吐槽大班课缺服务,1对1则强调其用户体验大小班课无人能及。仔细说来,各种说法均有道理,各种模式之间也确有短长。
刘旷
2020/12/18
3630
腾讯教育发布传统教培机构SaaS解决方案 即买即用 按需付费
2020年,是机遇与挑战并存的一年。对教育行业尤其是传统教培机构而言,变革和转型成为迫在眉睫的目标。9月10日,在腾讯全球数字生态大会智慧教育专场中,腾讯教育全面展示了为传统教培数字化转型服务的SaaS解决方案。 腾讯教育副总经理杨晖表示,即买即用、按需定制,都是SaaS模式的优势,能够快速解决传统教培机构系统搭建和技术积累较弱的痛点,且无需一次性投入大量精力和资金。一直以来,由腾讯自研的产品和方案,既帮助教育培训机构提升了自身的技术能力,也发挥了连接线上和线下用户和机构的重要作用。数据显示,腾讯已服务了
鹅老师
2020/09/14
1.6K0
人工智能火,AI培训班有存在的必要吗?
"被称为“业界良心”吴恩达在 Coursera 的免费机器学习课程,学员数目有超过两百万;而最近国内某人工智能教育平台创始人也在微博宣称其培训平台已经吸引到将近十万的付费学员。各种培训班名目众多,堪称 IT 业界一大奇象。我们在 AI 前线的社群里也经常见到这样的问题:想入门 AI,你们能推荐下培训班么?其实关于“培训班”、“如何转型 AI“、”AI 如何速成“,最有发言权的应该是用人单位和技术专家”。 Part1:一万元学费换几万元月工资? 众所周知,人工智能火爆了一整个 2017 年,将来极有可能要
机器人网
2018/04/18
3.9K0
人工智能火,AI培训班有存在的必要吗?
基于视频流传输 — 在线教育白板技术
大家好,我是来自学而思的赵文杰,现就职于学而思网校并担任架构师的工作,接下来我将为大家分享互动白板在在线教育上的应用。
LiveVideoStack
2021/09/01
1.9K0
在线解剖青蛙,亲历VR手术室​!牛津、北邮是如何上网课的?
前不久,大批小学生“进驻”互联网办公软件钉钉,网友表示,“不止是王者荣耀,小学生们已经开始对钉钉下手了!”下手也就算了,关键是下了狠手啊,小朋友们一气之下开始疯狂轰炸钉钉,评分只给1颗星。
大数据文摘
2020/03/10
6640
在线解剖青蛙,亲历VR手术室​!牛津、北邮是如何上网课的?
一个测开架构师的2022年个人年终总结
人常说“时间在流逝”。其实不对,时间是静止的,是我们在流逝。再回首,已记不得当初2022年“拍脑袋”定的flag了,无奈只能翻起2021年终总结才发现梦想很美好,现实很残酷。从上面的思维导图来看2022年总体还是朝着当初定的目标在前进,只是过程中有些计划定的太理想化了,导致可能最终完成的结果不太好,比如:目标跑300公里,实际才完成了94公里;目标口语能达到随机选一个话题能讲2分钟,实际也就1分钟就卡壳了。回想起工作中好像也是经常会发生这种情况,比如程序员每次评估需求所需的工时一样都非常乐观-,-,在我看来对于已知的事物我们都能比较准确的估算工时,但是对于未知的事物往往很难去评估,这也许就是PMI-ACP认证中提到的我们需要有“探针”来去评估风险,去平衡时间与资源的利用率,就像《精益产品开发》书中举的例子医院的医生与病人之间,到底应该是时间优先、还是资源优先,如何达到“最优”,对应于工作也是,质量是没有底的,我们如何去做“刚刚好”的质量,这是一门艺术,是我们需要用一生的时间不断学习、探索的过程。
TestOps
2023/03/03
5190
一个测开架构师的2022年个人年终总结
一周简报|腾讯云扶持小程序开发者,十分钟搭建开发环境
畅思SDK获2016金狗奖:最佳游戏整合营销企业奖;云适配成功入选首期正和岛“亿+计划”;Avaya携手容联领跑呼叫中心4.0时代,将深耕Saas服务市场;网易云信助力"家有学霸",升级在线教育多媒体
BestSDK
2018/02/28
3.5K0
一周简报|腾讯云扶持小程序开发者,十分钟搭建开发环境
推荐阅读
相关推荐
停课不停学浪潮下,线下教育机构如何转型线上,突出疫情重围
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档