Go语言的有效错误处理

中午闲暇翻看Daniel Morsing的“The Go scheduler”时,发现其另外一篇短文“Effective error handling in Go”,文章不长,但感觉对Go中错误处理方法总结的还是比较到位的,这里译之供大家参考。

一、简介

Go语言受到诟病最多的一项就是其错误处理机制。如果显式地检查和处理每个error,这恐怕的确会让人望而却步。你可以试试这里列出的几个方法,以避免你走入错误处理方法的误区当中去。

二、在缩进区处理错误

当使用Go语言编写代码时,首选下面这样的错误处理方法:

f, err := os.Open(path)
if err != nil {
    // handle error
}
// do stuff

而不是下面这样的:

f, err := os.Open(path)
if err == nil {
    // do stuff
}
// handle error

按照上面的方法处理错误,处理正常情况的代码读起来就显得通篇连贯了。

三、定义你自己的errors

做好如何正确进行错误处理的第一步就是要了解error是什么。如果你设计实现的包会因某种原因发生某种错误,你的包用户将会对错误的原因很感兴趣。为了满足用户的需求,你需要实现error接口,简单做起来就像这样:

type Error string
func (e Error) Error() string { return string(e) }

现在,你的包用户通过执行一个type assertion就可以知道是否是你的包导致了这个错误:

result, err := yourpackage.Foo()
if ype, ok := err.(yourpackage.Error); ok {
    // use ype to handle error
}

通过这个方法,你还可以向你的包用户暴露更多地结构化错误信息:

type ParseError struct {
    File  *File
    Error string
}

func (oe *ParseError) Error() string {//译注:原文中这里是OpenError
    // format error string here
}

func ParseFiles(files []*File) error {
    for _, f := range files {
        err := f.parse()
        if err != nil {
            return &ParseError{ //译注:原文中这里是OpenError
                File:  f,
                Error: err.Error(),
            }
        }
    }
}

通过这种方法,你的用户就可以明确地知道到底哪个文件出现解析错误了。(译注:从这里看到的go语言error设计之内涵,让我想起了Rob Pike大神的一篇Blog:"少即是级数级的多")

不过包装error时要小心,当你将一个error包装起来后,你可能会丢失一些信息:

var c net.Conn
f, err := DownloadFile(c, path)
switch e := err.(type) {
default:
    // this will get executed if err == nil
case net.Error:
    // close connection, not valid anymore
    c.Close()
    return e
case error:
    // if err is non-nil
    return err
}
// do other things.

如果你包装了net.Error,上面这段代码将无法知道是由于网络问题导致的失败,会继续使用这条无效的链接。

有一条经验规则:如果你的包中使用了一个外部interface,那么不要对这个接口中方法返回的任何错误,使用你的包的用户可能更关心这些错误,而不是你包装后的错误。

四、将错误作为状态

有时,当遇到一个错误时,你可能会停下来等等。这或是因为你将延迟报告错误,又或是因为你知道如果这次报告后,后续你会再报告同样的错误。

第一种情况的一个例子就是bufio包。当一个bufio.Reader遇到一个错误时,它将停下来保持这个状态,直到buffer已经被清空。只有在那时它才会报告错误。

第二种情况的一个例子是go/loader。当你通过某些参数调用它导致错误时,它会停下来保持这个状态,因为它知道你很可能会使用同样地参数再次调用它。

五、使用函数以避免重复代码

如果你有两段重复的错误处理代码,你可以将它们放到一个函数中去:

func handleError(c net.Conn, err error) {
    // repeated error handling
}

func DoStuff(c net.Conn) error {
    f, err := downloadFile(c, path)
    if err != nil {
        handleError(c, err)
        return err
    }

    f, err := doOtherThing(c)
    if err != nil {
        handleError(c, err)
        return err
    }
}

优化后的实现方法如下:

func handleError(c net.Conn, err error) {
    if err == nil {
        return
    }
    // repeated error handling
}

func DoStuff(c net.Conn) error {
    defer func() { handleError(c, err) }()
    f, err := downloadFile(c, path)
    if err != nil {
        return err
    }

    f, err := doOtherThing(c)
    if err != nil {
        return err
    }
}

这就是全部了。就Go语言错误处理而言,我知道的就这么多了。

Go,5周年

2014年11月10日(美国当地时间),Golang官方博客 放出了Andrew Gerrand的一篇博文《Half a decade with Go》来纪念Go语言发布五周年。文章按时间顺序简要描述了Golang这五年来发展的 点点滴滴,并让全世界Gopher看到了Go可期的光明未来。考虑到这篇文章在墙外,不便于国内Gopher阅读,这里给出中文翻译版,希望能给中国大陆 的Gophers带来些帮助!

五年前,我们启动了Go语言项目。我们准备发布第一版时的一幕仿佛就发生在昨天似的:我们的官方站点用的是一种可爱的黄色色调,我们将Go语言称为一门 “系统编程语言”,你需要使用分号作为语句结束标志,使用Makefile来构建你的代码。我们不知道Go语言是否能被大家接受。人们会分享我们的目标和 愿景吗?人们会发现Go语言有用吗?

起初,我们的发布引起了一阵关注。Google发布了一门新的编程语言,每个人都渴望探究它一番。一些程序员因为Go相对保守的功能特性集合而选择了放 弃,Go给他们的第一印象就是:没有什么新鲜玩意儿!但另外一小群程序员则看到了这个为软件工程师量身定做的生态系统的开端。这少数人将组成Go语言社区 的核心。

第一版发布后,我们花了些时间向社区传达Go语言背后的目标和设计理念。Rob Pike在官方的《Go at Google: Language Design in the Service of Software Engineering》一文中对此进行了生动地表达,并 在其个人博客文章《Less is exponentially more》中做了进一步的阐述。Andrew Gerrand的《Code that grows with grace》(Slides在这里)和《Go for Gophers》(Slides在这里)对Go的设计哲学又给出了更有深度和技术性的说明。

随着时间的推移,积少成多。这个项目的转折点出现在2012年3月Go 1发布时。Go 1为程序员们提供了可以信赖的稳定的语言和标准库。到2014年,Go项目拥有了上百的核心贡献者,其生态圈中拥有了数不尽的第三方库和工具 ,并由成千上万的开发者维护着。正在发展壮大的社区拥有许多极具热情的成员(或者就如我们所称呼 的:Gophers)。今天,就我们目前的统计分析,Go社区的成长速度远远超出了我们的预期。

Gophers们在哪里可以得到这些呢?全世界目前有很多有关Go语言的“大事”发生。今年我们看到了几个专门的Go技术大会:在丹佛和巴黎举行的首次 GopherCondotGo大 会。FOSDEM的Go DevRoom以及在东京举行的一年两次的GoCon。每次会上来自全球各地的Gophers们都踊跃地展示他们开发的Go项目。对于Go语言开发组来 说,我们很高兴能满足这些分享我们愿景和兴奋的程序员的需求。

在世界各地,还有数十个社区驱动运行的“Go用户组”。如果你还没有造访过你当地的用户组,可以考虑去尝试一下。如果你当地尚没有这类用户组,也许你可以考虑发起一个

今天,Go在云端找到了用武之地。Go出现在了工业向云计算转型的时刻。并且我们兴奋地看到Go正在快速成为这个运动的一个重要组成部分。简单、高效、内 置并发原语和现代的标准库让Go语言尤其适合云端软件开发(毕竟它就是为此而设计的)。一些重量级的开源云项目,诸如Docker和Kubernetes 都是用Go语言实现的,一些运作基础设置的公司,诸如Google、CloudFlare、Canonical、Digital Ocean、Github、Heroku以及微软也都在使用Go语言开发一些重量级的项目。

那么将来会怎样呢?我们认为2015年将是Go语言大爆发的一年。

Go 1.4,除了其新增的特性和bug修正外,它为实现一个新的低延迟垃圾收集器以及支 持在移动终端上运行Go奠定了基础。 预计Go1.4将在2014年12月1日正式发布。我们期望在Go 1.5中能出现新GC的身影,Go 1.5预计在2015年6月1日发布,它将使Go适合更加广泛的应用开发。我们迫不及待的想看到哪些领域的开发者会接受它。

接下来会有更多的Go大事发生。11月15日,GothamGo将在纽约如期举行。2014年1月31日到 2月1日,布鲁塞尔将举行另一次Go DevRoot at FOSDEM。2015年2月19日到21日,在印度班加罗尔将举行GopherCon India大会。最初的GopherCon将在2015年7月份回到丹佛。2015年11月 dotGo大会将再次来到巴黎。

Go团队将向届时到场的所有gophers表示衷心的感谢。为Go语言的下一个五年!

为了庆祝Go诞生5周年,在未来的一个月里,Gopher Academy将会发布一系列由知名Go users撰写的文章,务必要去看看哦。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats