当前位置:首页 > 科技  > 软件

聊聊Golang饱受争议的Error

来源: 责编: 时间:2023-11-06 17:20:06 402观看
导读一、error是什么?在C中,返回错误通过errno.h中的错误代码来表示,比如0代表No error,也就是没有错误;2代表No such file or directory,也就是找不到指定路径的文件或文件夹;5代表Input/Output error,表示输入或输出出现了错误.

一、error是什么?

在C中,返回错误通过errno.h中的错误代码来表示,比如0代表No error,也就是没有错误;2代表No such file or directory,也就是找不到指定路径的文件或文件夹;5代表Input/Output error,表示输入或输出出现了错误...LL728资讯网——每日最新资讯28at.com

而在我们最爱的Golang中,有这样一个饱受争议的error类型,它不是一个整数,而是一个接口。LL728资讯网——每日最新资讯28at.com

package mainimport (    "errors"    "fmt")type name struct {    error string}func (n *name) Error() string {    return fmt.Sprintf("%s : ...", n.error)}func main() {        err := judge(11)    //err := judge(1)    //err := judge(6)    fmt.Println(err)}func judge(num int) error {    if num > 5 && num < 10 {        return errors.New("这个数字大于5了..")    }    if num >= 10 {        return fmt.Errorf("%d大于或等于10了...", num)    }    return &name{error: "hello"}}

这是三种可以作为error返回值的方式。errors.New()创建出来的error类型其实是errorString结构体。LL728资讯网——每日最新资讯28at.com

// src/errors/errors.go// 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}

所以我们创建的结构体name其实和errors.New()底层的形式是基本一样的。LL728资讯网——每日最新资讯28at.com

而使用的fmt.Errorf其实是先将字符串格式化然后再调用errors.New()。LL728资讯网——每日最新资讯28at.com

二、error引人争论的点在哪?

在Go中,设计者从语言层面要求人们需要明确地处理遇到的错误,但是因此导致的问题也十分明显,使用Go语言编写的代码中err会到处都是,不过优秀的IDE——Goland能够解决这个问题,使用Goland能够将err!=nil这段判断和处理压缩,不再干扰代码的阅读。LL728资讯网——每日最新资讯28at.com

我本人是不太喜欢Java的try-catch机制,可能是不太会用,Go语言官方提到try-catch会让代码变得比较混乱,很多程序员会胡乱catch异常,导致错误处理比较冗长。LL728资讯网——每日最新资讯28at.com

而Go语言通过多返回值机制,让返回错误变得很简单,并且提供panic和error两种机制,感觉这种机制更有优势,也看起来更简洁。LL728资讯网——每日最新资讯28at.com

煎鱼大佬之前有博客谈到了Go社区中关于Go错误处理的新议题,大家想了解的可以看看:LL728资讯网——每日最新资讯28at.com

  • Go 错误处理新思路?用左侧函数和表达式:https://juejin.cn/post/7102268049213882398
  • Go try 新提案靠谱吗?想简化错误处理了 https://juejin.cn/post/7157931922008571940

其实之前Go社区中出现过多种关于错误处理的新议题,但是都没有被采纳...LL728资讯网——每日最新资讯28at.com

三、如何优雅的处理错误

1. 避免处理“哨兵错误”,即Sentinel errors

比如为了判断err == io.EOF就得引入io包,这是标准库的包还能接受,如果是第三方库的包,并且使用“哨兵错误”,很容易导致循环引用的问题。LL728资讯网——每日最新资讯28at.com

2. 避免使用error类型

虽然这种错误比“哨兵错误”要好,它可以捕获更多关于错误的上下文信息,比如出错的行数等其他字段信息。但是又不可避免地在定义错误和使用错误的包之间形成依赖关系,又容易导致循环引用的问题。LL728资讯网——每日最新资讯28at.com

3. 使用不透明的“黑盒错误”
func f() error{    sentence,err := say.Hello()    if err != nil{        return err    }    // ...}

上面这种写法是不是我们经常会用到?这种情况下,我们只需要判断err是否为空,不为空,代表有错误,就直接返回错误,否则就继续执行后面的流程。LL728资讯网——每日最新资讯28at.com

作为程序执行者,你没有能力看到程序错误的内部信息,只能知道程序有错或者没有错误。这种错误处理作为一种调试辅助手段还是不错的。LL728资讯网——每日最新资讯28at.com

4. 使用Warp和Cause

第三方库github.com/pkg/errors可以输出错误堆栈,并且使用起来很简单,大家可以了解一下。LL728资讯网——每日最新资讯28at.com

// Wrap annotates cause with a message.func Wrap(cause error, message string) error// Cause unwraps an annotated error.func Cause(err error) error

下面来介绍Wrap和Cause的使用样例:LL728资讯网——每日最新资讯28at.com

func ReadFile(path string) ([]byte, error) {        f, err := os.Open(path)        if err != nil {                return nil, errors.Wrap(err, "open failed")        }        defer f.Close()        buf, err := ioutil.ReadAll(f)        if err != nil {                return nil, errors.Wrap(err, "read failed")        }        return buf, nil}func ReadConfig() ([]byte, error) {        home := os.Getenv("HOME")        config, err := ReadFile(filepath.Join(home, ".settings.xml"))        return config, errors.Wrap(err, "could not read config")}func main() {        _, err := ReadConfig()        if err != nil {                fmt.Println(err)                os.Exit(1)        }}

如果ReadConfig()执行失败,就会得到下面这一行十分美观的报错:LL728资讯网——每日最新资讯28at.com

could not read config: open failed: open /Users/dfc/.settings.xml: no such file or directory

而如果用fmt.Printf和%+v格式来输出就能看到更清晰、更有层次的错误堆栈:LL728资讯网——每日最新资讯28at.com

func main() {        _, err := ReadConfig()        if err != nil {                fmt.Printf("%+v",err)                os.Exit(1)        }}

图片图片LL728资讯网——每日最新资讯28at.com

然后我们再来看Cause的使用。LL728资讯网——每日最新资讯28at.com

type temporary interface{    Temporary() bool}// IsTemporary returns true if err is temporary.func IsTemporary(err error) bool {        te, ok := errors.Cause(err).(temporary)        return ok && te.Temporary()}

当需要检查一个错误与一个特定的值或类型时。比如此处,先用Cause取出错误,做断言,最后调用Temporary(),如果断言失败,ok就会是false,就不会调用右边的Temporary()去执行。LL728资讯网——每日最新资讯28at.com

如果 && 运算符左侧的子表达式为 false,则不会检查右侧的表达式。因为只要有一个子表达式为 false,则整个表达式都为 false,所以再检查剩余的表达式会浪费 CPU 时间。这被称为短路评估。LL728资讯网——每日最新资讯28at.com

本文转载自微信公众号「 程序员升级打怪之旅」,作者「 丘山子&王中阳Go」,可以通过以下二维码关注。LL728资讯网——每日最新资讯28at.com

LL728资讯网——每日最新资讯28at.com

转载本文请联系「 程序员升级打怪之旅」公众号。LL728资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-17287-0.html聊聊Golang饱受争议的Error

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 快速了解CSS 相对颜色

下一篇: 开发微服务的九个最佳实践

标签:
  • 热门焦点
  • 掘力计划第 20 期:Flutter 混合开发的混乱之治

    在掘力计划系列活动第20场,《Flutter 开发实战详解》作者,掘金优秀作者,Github GSY 系列目负责人恋猫的小郭分享了Flutter 混合开发的混乱之治。Flutter 基于自研的 Skia 引擎
  • 让我们一起聊聊文件的操作

    文件【1】文件是什么?文件是保存数据的地方,是数据源的一种,比如大家经常使用的word文档、txt文件、excel文件、jpg文件...都是文件。文件最主要的作用就是保存数据,它既可以保
  • 微信语音大揭秘:为什么禁止转发?

    大家好,我是你们的小米。今天,我要和大家聊一个有趣的话题:为什么微信语音不可以转发?这是一个我们经常在日常使用中遇到的问题,也是一个让很多人好奇的问题。让我们一起来揭开这
  • 2天涨粉255万,又一赛道在抖音爆火

    来源:运营研究社作者 | 张知白编辑 | 杨佩汶设计 | 晏谈梦洁这个暑期,旅游赛道彻底火了:有的「地方」火了&mdash;&mdash;贵州村超旅游收入 1 个月超过 12 亿;有的「博主」火了&m
  • 消费结构调整丨巨头低价博弈,拼多多还卷得动吗?

    来源:征探财经作者:陈香羽随着流量红利的退潮,电商的存量博弈越来越明显。曾经主攻中高端与品质的淘宝天猫、京东重拾&ldquo;低价&rdquo;口号。而过去与他们错位竞争的拼多多,靠
  • 花7万退货退款无门:谁在纵容淘宝珠宝商家造假?

    来源:极点商业作者:杨铭在淘宝购买珠宝玉石后,因为保证金不够赔付,店铺关闭,退货退款难、维权无门的比比皆是。&ldquo;提供相关产品鉴定证书,支持全国复检,可以30天无理由退换货。&
  • 大厂卷向扁平化

    来源:新熵作者丨南枝 编辑丨月见大厂职级不香了。俗话说,兵无常势,水无常形,互联网企业调整职级体系并不稀奇。7月13日,淘宝天猫集团启动了近年来最大的人力制度改革,目前已形成一
  • 当家的盒马,加速谋生

    来源 | 价值星球Planet作者 | 归去来自己&ldquo;当家&rdquo;的盒马,开始加速谋生了。据盒马官微消息,盒马计划今年开放生鲜供应链,将其生鲜商品送往食堂。目前,盒马在上海已经与
  • Meta盲目扩张致超万人被裁,重金押注元宇宙而前景未明

    图片来源:图虫创意日前,Meta创始人兼CEO 马克&middot;扎克伯发布公开信,宣布Meta计划裁员超11000人,占其员工总数13%。他公开承认了自己的预判失误:&ldquo;不仅
Top