Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Golang 语言怎么处理错误?

Golang 语言怎么处理错误?

作者头像
frank.
发布于 2021-03-09 10:21:41
发布于 2021-03-09 10:21:41
1.4K00
代码可运行
举报
运行总次数:0
代码可运行

01

介绍

golang 程序大多数是通过 if err != nil 处理错误,在 golang 社区中,有一部分 golang 程序员对此举是持反对观点,他们认为在 golang 代码中存在大量的错误处理代码 if err != nil,使整体代码变得非常不优雅,应该在 golang 中引入其他处理错误的机制,例如 try-catche 或其它此类处理错误的机制。其实,他们忽略了 golang 中一个特别重要的概念,即 errors are values,并且 golang 作者 Rob Pike 也对此问题做出过回应,在 golang 代码中出现重复的错误处理代码 if err != nil,可能是 golang 用户的使用方式有问题。

本文我们主要聊聊在 golang 中,怎么处理错误?

02

golang 定义错误的两种方式

使用 golang 标准库 errors 的 New() 函数,可以定义一个错误类型的变量。

func New(text string) error

New() 函数接收一个 string 类型的文本,返回一个 error 类型的变量。即使给定的文本不同,每次对 New() 函数的调用也会返回不同的错误值。

关于每次调用 New() 函数,都可以返回不同的错误值,golang 是怎么做到的呢?我们通过阅读 golang 的源码,找一下我们的问题答案。

源码 /usr/local/go/src/errors/errors.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// New returns an error that formats as the given text.
// Each call to New returns a distinct error value even if the text is identical.
func New(text string) error {
 return &errorString{text}
}

// errorString is a trivial implementation of error.
type errorString struct {
 s string
}

func (e *errorString) Error() string {
 return e.s
}

源码中,我们发现 New() 函数体中的代码是返回一个指针类型 &errorString{text},所以我们的疑问自然有了答案。

那么,golang 中定义错误的另外一种方式是什么?在 golang 标准库 fmt 中,通过调用 Errorf() 函数也可以返回一个 error 类型的错误。

源码 /usr/local/go/src/fmt/errors.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func Errorf(format string, a ...interface{}) error {
 p := newPrinter()
 p.wrapErrs = true
 p.doPrintf(format, a)
 s := string(p.buf)
 var err error
 if p.wrappedErr == nil {
  err = errors.New(s)
 } else {
  err = &wrapError{s, p.wrappedErr}
 }
 p.free()
 return err
}

03

错误处理方式之“不透明错误处理”

正如我们在文章开篇所述,在 golang 程序中,我们见的最多的错误处理方式就是 if err != nil,此种错误处理方式,错误处理方不关心错误提供方的错误值。因此,我们将此种错误处理方式称为“不透明错误处理”。

示例代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
err := errors.New("this is a error example")
if err != nil {
 fmt.Println(err)
  return
}

04

golang 1.13 新增 As() 函数

在 golang 1.13 中,新增 As() 函数,当 error 类型的变量是一个包装错误(wrap error)时,它可以顺着错误链(error chain)上所有被包装的错误(wrapped error)的类型做比较,直到找到一个匹配的错误类型,并返回 true,如果找不到,则返回 false。

通常,我们会使用 As() 函数判断一个 error 类型的变量是否为特定的自定义错误类型。

示例代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 自定义的错误类型
type DefineError struct {
 msg string
}

func (d *DefineError) Error() string {
 return d.msg
}

func main() {
  // wrap error
 err1 := &DefineError{"this is a define error type"}
 err2 := fmt.Errorf("wrap err2: %w\n", err1)
 err3 := fmt.Errorf("wrap err3: %w\n", err2)
 var err4 *DefineError
 if errors.As(err3, &err4) {
  // errors.As() 顺着错误链,从 err3 一直找到被包装最底层的错误值 err1,并且将 err3 与其自定义类型 `var err4 *DefineError` 匹配成功。
  fmt.Println("err1 is a variable of the DefineError type")
  fmt.Println(err4 == err1)
  return
 }
 fmt.Println("err1 is not a variable of the DefineError type")
}

05

golang 1.13 新增 Is() 函数

在 Part03 中,我们讲述了“不透明错误处理”的错误处理方式,错误处理方不关心错误提供方的错误值。但是,在错误处理方需要关心错误提供方的错误值时,错误处理方要对错误提供方的错误值进行判定,这就造成了代码的耦合,错误提供方的错误值每次修改,错误处理方都需要跟着做出相应修改。

针对这种情况,golang 一般会采用“哨兵错误处理”的错误处理方式,即定义可导出的错误变量,错误处理方和错误提供方都只操作错误变量,这样做的好处是只需维护错误变量,但是还没有彻底解决问题,如果 error 类型的错误变量是一个包装错误(wrap error),“哨兵错误处理”的错误处理方式也不方便处理该错误。

好在 golang 1.13 新增 Is() 函数,它可以顺着错误链(error chain)上所有被包装的错误(wrapped error)的类型做比较,直到找到一个匹配的错误。

示例代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 哨兵错误处理
var (
 ErrInvalidUser     = errors.New("invalid user")
 ErrNotFoundUser    = errors.New("not found user")
)

func main () {
  err1 := fmt.Errorf("wrap err1: %w\n", ErrInvalidUser)
 err2 := fmt.Errorf("wrap err2: %w\n", err1)
  // golang 1.13 新增 Is() 函数
 if errors.Is(err2, ErrInvalidUser) {
  fmt.Println(ErrInvalidUser)
  return
 }
 fmt.Println("success")
}

06

总结

本文我们开篇先是讲述了 golang 社区中,存在对待 golang 错误处理方式的反对态度的用户,这么一个客观事实。接着,我们介绍了 golang 中的两种定义错误的方式和底层源码实现,和 golang 1.13 中新增的关于错误处理的函数。如果你现在使用的是 golang 1.13 及以上版本,请使用 As()Is()

通过阅读源码 /usr/local/go/src/errors/wrap.go,我们可以发现 As()Is() 是通过在错误链中不断调用 Unwrap() 函数,最终找到匹配的错误值。其中,Unwrap() 函数也是在 golang 1.13 中新增的函数。

Unwrap() 函数的源码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Unwrap returns the result of calling the Unwrap method on err, if err's
// type contains an Unwrap method returning error.
// Otherwise, Unwrap returns nil.
func Unwrap(err error) error {
 u, ok := err.(interface {
  Unwrap() error
 })
 if !ok {
  return nil
 }
 return u.Unwrap()
}

推荐阅读:

Go 语言学习之错误处理

Golang 语言的标准库 log 包怎么使用?

Golang 语言三方库 lumberjack 日志切割组件怎么使用?

Golang 语言标准库 bytes 包怎么使用?

Golang 语言的标准库 os 包怎么操作目录和文件?

参考资料: https://golang.org/pkg/errors/

延伸阅读: https://blog.golang.org/error-handling-and-go https://blog.golang.org/errors-are-values https://blog.golang.org/go1.13-errors https://golang.org/doc/tutorial/handle-errors https://medium.com/rungo/error-handling-in-go-f0125de052f0 https://www.digitalocean.com/community/tutorials/handling-errors-in-go

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-02-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Go语言开发栈 微信公众号,前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
React Native在美团外卖客户端的实践
美团研发团队基于React Native开源框架,并结合美团业务场景,定制化开发了一套动态化方案。本文主要分享该动态化方案在美团外卖业务场景中的实践,希望能给大家一些启发。
美团技术团队
2019/12/23
2.3K0
React Native在美团外卖客户端的实践
美团智能支付稳定性测试实战
本文介绍了美团智能支付业务在稳定性方向遇到的挑战,并重点介绍QA在稳定性测试中的一些方法与实践。
美团技术团队
2019/01/09
1.4K0
美团配送实时特征平台建设实践
导读:2019年5月,美团正式推出新品牌「美团配送」,升级配送开放平台。那你知道支撑美团配送大脑的实时特征平台是如何建设的吗?如何实现每分钟生产千万级的实时特征?如何在70w+QPS的场景下实现4个9响应耗时在50毫秒的需求?本文将为大家介绍配送实时特征平台的发展历程,关键技术和实践经验。
Houye
2021/01/27
1.5K0
美团配送实时特征平台建设实践
系统总出故障怎么办,或许你该学学稳定性建设!
说到系统稳定性,不知道大家会想起什么?我想大多数人会觉得这个词挺虚的,不知道系统稳定性指的是什么。一年前的我看到这个词,也是类似于这样的感受,大概只知道要消除单点、做好监控报警,但却并没有一个体系化的方法论。经过一段时间的摸索,我对系统稳定性有了较为体系化的认识,于是迫不及待地希望和大家一起分享。所以今天,就让我跟大家简单聊聊系统稳定性建设这个话题吧!
陈树义
2022/09/08
8340
系统总出故障怎么办,或许你该学学稳定性建设!
美团高性能终端实时日志系统建设实践
你是否经常遇到线上需要日志排查问题但迟迟联系不上用户上报日志的情况?或者是否经常陷入由于存储空间不足而导致日志写不进去的囧境?本文介绍了美团是如何从0到1搭建高性能终端实时日志系统,从此彻底解决日志丢失和写满问题的。希望能为大家带来一些帮助和启发。
美团技术团队
2022/12/16
9560
美团高性能终端实时日志系统建设实践
美团外卖自动化业务运维系统——Alfred
背景 美团外卖业务在互联网行业是非常独特的,不仅流程复杂——从用户下单、商家接单到配送员接单、交付,而且压力和流量在午、晚高峰时段非常集中。同时,外卖业务的增长非常迅猛,自2013年11月上线到最近峰
美团技术团队
2018/03/13
1.9K0
美团外卖自动化业务运维系统——Alfred
美团外卖订单中心的演进 转
美团外卖从2013年9月成交第一单以来,已走过了三个年头。期间,业务飞速发展,美团外卖由日均几单发展为日均500万单(9月11日已突破600万)的大型O2O互联网外卖服务平台。平台支持的品类也由最初外卖单品拓展为全品类。
chinotan
2019/04/03
1.1K0
美团即时物流的分布式系统架构设计
本文根据美团资深技术专家宋斌在ArchSummit架构师峰会上的演讲整理而成,主要介绍在美团即时物流分布式系统架构逐层演变的进展中,遇到的技术障碍和挑战,还有我们的解决思路。
美团技术团队
2019/01/07
1.1K0
美团点评智能支付核心交易系统的可用性实践
每个系统都有它最核心的指标。比如在收单领域:进件系统第一重要的是保证入件准确,第二重要的是保证上单效率。清结算系统第一重要的是保证准确打款,第二重要的是保证及时打款。我们负责的系统是美团点评智能支付的核心链路,承担着智能支付100%的流量,内部习惯称为核心交易。因为涉及美团点评所有线下交易商家、用户之间的资金流转,对于核心交易来说:第一重要的是稳定性,第二重要的还是稳定性。
静儿
2018/05/24
2.7K4
美团即时物流的分布式系统架构设计
美团外卖已经发展了五年,即时物流探索也经历了3年多的时间,业务从零孵化到初具规模,在整个过程中积累了一些分布式高并发系统的建设经验。最主要的收获包括两点:
美团技术团队
2018/11/23
1.5K0
美团即时物流的分布式系统架构设计
大神分享美团外卖订单中心演进之路
作者:何轼 来源: http://tech.meituan.com/mt_waimai_order_evolution.html 前言 美团外卖从2013年9月成交首单以来,已走过了三个年头。时期,事
小小科
2018/05/04
2.9K1
大神分享美团外卖订单中心演进之路
智能支付稳定性测试实战
美团支付承载了美团全部的交易流量,按照使用场景可以将其分为线上支付和智能支付两类业务。线上支付,支撑用户线上消费场景,处理美团所有线上交易,为团购、外卖、酒店旅游等业务线提供支付能力;智能支付,支撑用户到店消费场景,处理美团所有线下交易,通过智能POS、二维码支付、盒子支付等方式,为商家提供高效、智能化的收银解决方案。其中,智能支付作为新扩展的业务场景,去年也成为了美团增速最快的业务之一。
美团技术团队
2018/12/14
1.1K0
智能支付稳定性测试实战
美团外卖持续交付的前世今生
美团外卖自2013年创建以来,业务一直在高速发展,从早期单一的美食业务发展成为包含闪购、跑腿、闪付、营销、广告等在内的平台业务。每个业务团队虽然都有不同的业务形态,但是几乎都有相同的诉求:需求能不能尽快的上线?本文将从外卖的历史实践中,浅谈一个好的持续交付需要综合考虑哪些关键因素,希望对大家有所帮助或启发。
美团技术团队
2020/02/19
1.6K0
美团外卖持续交付的前世今生
美团即时物流的分布式系统架构设计
美团外卖已经发展了五年,即时物流探索也经历了3年多的时间,业务从零孵化到初具规模,在整个过程中积累了一些分布式高并发系统的建设经验。最主要的收获包括两点:
物流IT圈
2019/07/16
1K0
美团即时物流的分布式系统架构设计
万字详解高可用架构设计
系统高可用是一个宏大的命题,从设计思想、架构原则到工程能力、服务管理等等方方面面,每个视角单拆出来都不是一篇文章可以解决的。本文将从大局上全面系统地梳理高可用系统架构,起到一个提纲挈领的作用。
腾讯云开发者
2025/01/07
3.1K0
万字详解高可用架构设计
美团大规模微服务通信框架及治理体系OCTO核心组件开源
微服务通信框架及治理平台OCTO作为美团基础架构设施的重要组成部分,目前已广泛应用于公司技术线,稳定承载上万应用、日均支撑千亿级的调用。业务基于OCTO提供的标准化技术方案,能够轻松实现服务注册/发现、负载均衡、容错处理、降级熔断、灰度发布、调用数据可视化等服务治理功能。
美团技术团队
2019/08/15
1.2K0
美团大规模微服务通信框架及治理体系OCTO核心组件开源
全链路压测平台(Quake)在美团中的实践
在美团的价值观中,“以客户为中心”被放在一个非常重要的位置,所以我们对服务出现故障越来越不能容忍。特别是公司业务正处在高速增长的阶段,每一次故障对公司来说都是一笔不小的损失。而整个IT基础设施非常复杂,包括网络、服务器、操作系统以及应用层面都可能出现问题。在这种背景下,我们必须对服务进行一次全方位的“体检”,从而来保障美团多个业务服务的稳定性,提供优质的用户服务体验。真正通过以下技术手段,来帮助大家吃的更好,生活更好:
美团技术团队
2019/04/04
2.3K0
全链路压测平台(Quake)在美团中的实践
美团外卖广告智能算力的探索与实践(二)
总第506篇 2022年 第023篇 在深度学习时代,算力的需求和消耗日益增长,如何降低算力成本,提高算力效率,逐渐成为一个重要的新课题。智能算力旨在对流量算力进行精细化和个性化分配,从而实现系统算力约束下的业务收益最大化。 本文主要介绍了美团外卖广告智能算力从线性规划算法到进化算法的技术演进过程,给出了一种基于进化算法的多动作算力分配方案,希望能给大家带来一些帮助或者启发。 1 业务背景 2 整体思路 2.1 算力分配问题形式化描述 2.2 挑战分析 3 方案设计 3.1 全链路最优算力决策 3.2 系
美团技术团队
2022/04/29
9980
美团外卖广告智能算力的探索与实践(二)
美团外卖Android Crash治理之路
Crash率是衡量一个App好坏的重要指标之一。如果你忽略了它的存在,它就会得寸进尺,愈演愈烈,最后造成大量用户的流失,进而给公司带来无法估量的损失。本文讲述美团外卖Android客户端团队在将App的Crash率从千分之三做到万分之二过程中所做的大量实践工作,抛砖引玉,希望能够为其他团队提供一些经验和启发。
美团技术团队
2018/08/01
1.2K0
美团外卖Android Crash治理之路
高可用 兜底方案
对于秒杀系统来说,在大流量的迅猛冲击下,都曾经或多或少发生过宕机的情况。当一个系统面临持续的大流量时,它其实很难单靠自身调整来恢复状态,你必须等待流量自然下降或者人为地把流量切走才行,这无疑会严重影响用户的购物体验
BUG弄潮儿
2021/09/10
1.4K0
高可用 兜底方案
推荐阅读
相关推荐
React Native在美团外卖客户端的实践
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验