Go 语言错误处理的姿势

2021-10-03 17:26:51 +08:00
 nanmu42

各位好。

前段时间看到 v2 上有个帖子,询问如何在 Go 中为错误加上堆栈,我以前也为类似的问题困扰过,后来找到了 pkg/errors ,再后来官方库有了 fmt.Errorf() ,我把这个小小经验写了下来,希望能抛砖引玉,欢迎各位交流拍砖。

在这篇文章中,我们将区分错误( error )和异常( panic ),讨论什么样的错误是“好”的(容易检查和排错),介绍一种让错误变“好”的常用方式(fmt.Errorf())。

谢谢。

4843 次点击
所在节点    Go 编程语言
51 条回复
lesismal
2021-10-05 00:55:03 +08:00
@XTTX #19 如果这样讲的话,那你也看一下,你在之前有提到过 naked return 吗?你看看一楼没有提把?你一楼的更让人想到的是返回值那里的变量声明而不是 naked return 。js2854 #10 的回复也是声明相关的而不是 naked return 。如果要细聊,那就聊明白点。而且,你确实没有 at 我进行回复,但是刚好是在我下一楼,你谁都没 at,我以为是回复我呢。即使不是回复我,你贴出来的链接,或者可以用来以上与你相关的所有人?那沟通技巧也可以提高下。想让别人看清楚再来杠,自己也要尽量把事情说清楚,否则别人也很难看清楚。

另外,对于我个人的感觉,函数定义的地方的返回值声明,比 naked return 让人阅读障碍更大。

再另外,你看下我贴的这个:
github.com/golang/go/blob/master/src/bufio/bufio.go#L169
你再往下看几行,std 到底有没有:
github.com/golang/go/blob/master/src/bufio/bufio.go#L174

纸上得来终觉浅,不要只看一些观点性的东西就轻易下一些结论
lesismal
2021-10-05 01:07:39 +08:00
@XTTX
第一,你一楼不管是指 named 还是 naked,我个人都没想反驳,挺对的。但后面提到的 std 里只有一种,用词太武断了,所以随口回了一句。
第二,这个语法,虽然别扭,但并不是什么高级玩意,你 #12 的语气,是带着不屑的,对于不是什么高级货的东西的不屑,没什么必要,真要是牛逼的东西你懂别人不懂,那你狂忍你狂,我举双手支持你的强。但这点玩意如果也觉得值得炫耀的,那可能是出于瓢的阶段了,刚好又是在我下一楼以为是回复我,所以才会连回了几个。

这个帖子浪费我太多积分了,不再回复了。有兴趣的欢迎来我的项目交流:
github.com/lesismal/nbio (可以拿 evio/gev/gnet,以及 gobwas/ws 等来对比看看)
github.com/lesismal/arpc
相关话题(压测请不要看各个仓库展示的数据,以自己代码实测为准):
colobu.com/2021/08/01/benchmark-of-rpc-frameworks
nanmu42
2021-10-05 09:26:58 +08:00
@ZSeptember 你说得对,我这篇文章对错误的识别处理说得太少了,标题有问题。感谢提醒。
pkg/errors 里有个 Cause()方法,在 Go 1.13 前用来做错误识别还是很趁手的。
XTTX
2021-10-05 18:34:08 +08:00
@lesismal 你回复的莫名其妙的。你自己不觉得很迷吗?我不想再解释也不是对你说的, 我对那位上来就反对然后不举证的老铁说的。 你非要对号入座。你觉得例子你觉得是很好的例子吗? 里面一会 named return , 一会又用另一个方式,named return 里一会 return , 一会又完整列出来。 你喜欢就这么写好了,我只是说我知道一些团队特意禁止这种方式。你自己不那么写,还要浪费那么多时间找些不好的例子, 就为打我的脸?您是真的迷
lesismal
2021-10-05 18:51:34 +08:00
站长说的对,不要浪费时间在没意义上的人和事情上。观点都描述不清楚,到现在都没听明白你到底是说 named 还是 naked,自己也没 at 别人刚好在我楼下而且语气可以被当成是回复上面相关人的,自己都不反思下表达能力么。
怪不得编译器厂招聘帖子里一堆人怼你

block 了先
lesismal
2021-10-05 19:34:20 +08:00
反思,反思,少回帖,只在 V 站攒积分少 BB 。虽然还是想知道 “std 里只有一种” 到底指的是什么,但是我放弃。

我昔所造诸恶业,皆有无始贪嗔痴。

戒骄戒躁,继续安心写自己喜欢的东西,向站长学习。
XTTX
2021-10-05 19:45:00 +08:00
哈哈哈,你是最棒的呢。
gogogo1203
2021-10-05 19:50:46 +08:00
@lesismal 1.自己都不用方式 return 方式,花时间去翻一些代码出来想打脸。2. 会去翻一大篇过去的贴来攻击,r 不是显得你更蠢。3. 你真是闲得慌,这帖子一开始就跟你无关,非要强行对号入座。4. 最后还来一堆圣母。5. 你是真的 6666
lesismal
2021-10-05 20:49:47 +08:00
@gogogo1203 #20
1. 我的确不用这种方式,但是你能看懂 #10 是回复的这句不:“standard libs 都用一种方式是有原因的。”?我希望既然聊技术严谨一点,不要没怎么看过源码就随口说源码怎么样,或者其他类似的观点,因为大家信誓旦旦言之凿凿的观点,可能会对其他人造成误导。
2. 不是翻帖子,而是之前就看过那个帖子,感觉一楼可能还相对经验欠缺、讨论技术的时候自己没太搞懂知识点就随口说了,然后加上我上一条看到他说的这个观点,所以觉得应该回复一下,但是回复了几次,一楼都没有说清楚到底他说的 “standard libs 都用一种方式是有原因的。” 中的这种方式是指什么,或者也可能我理解能力太差、一楼已经在后续回复中讲清楚了但是我没 get 到,如果是这样,那各位可以指正,我虚心接受。
3. 我上面回复了帖子,对方在我下一楼没有 at 任何人,我也没太关注他们之前的讨论,而且我下一楼的回复中的内容也可以用来回复我的内容,并且语气带着轻浮,参考我本次回帖第 2 条中的出发点,所以觉得有必要多回复一些。
4. 你确认圣母这个词符合你用在这里的场景吗?

另外,如果本来帖子与我无关、我自己“强行对号入座”,那我对号入座跟阁下又有什么关系呢?而且我前面几次回复中也解释过了为啥我会回复好几段。你倒是也挺有时间得嘛,或者你可能也没仔细看我前面回的内容没分析我和一楼多次对话中的内容吧~

@XTTX 小伙子心态蛮好的,我喜欢,大过节的,不吵了,没必要,如果造成不适,我抱歉,请见谅。但该严谨还是建议严谨
lesismal
2021-10-05 21:05:52 +08:00
@gogogo1203 #28 上一楼是回复 28 楼,写错了写成 20 。
补充一下,我没花多少时间故意翻源码打脸之类的,因为平时就经常源码,也正是因为以前就隔三差五在源码中看到类似的写法,所以看到 #9 说只用一种方式的时候,才会第一时间觉得不严谨。

今年完善了一份 poller 的框架,几年前比较火的一个老外的关于 golang websocket 百万连接的帖子和相关的 gobwas/ws 都是存在缺陷的方案,我这个实现了完整的异步流解析 tls/http1.x/websocket,能够解决 golang 1000k 问题。对比其他 golang 非阻塞 io 框架,他们都还没有支持这些,并且单就网络库部分的性能,基本高于其他库,易用性扩展性都更强。吹个牛逼说,目前全网独一份,不信你可以去看 evio/gev/gnet/easygo,还有字节的 netpoll,或者也去找找有没有其他库,做下对比,看看他们有没有支持这么多功能。
或者不必功能支持完整度,单就性能对比下:
https://github.com/lesismal/go-net-benchmark

这些花费了我很多时间,还在持续打磨,社交确实会消耗很多精力,所以才会有 #26 反思。你如果觉得我很闲,可以粗略看下我的几个库相关的,再看看我是不是很闲

当然,对于这个帖子消耗了这么多时间,确实是犯二了,我继续反思。
XTTX
2021-10-05 23:16:08 +08:00
@lesismal 我所有的回复都是针对这个人的这个话 ”@XTTX 这不是 go 的常见做法么,还能写出啥花样?" 。 所有的 std libs 都有明确的 return 。所有的事都有 corner case. 你自己举例的代码都来回混用,肯定不是值得推荐的写代码的方式,反而是一个 readability 的反例。 一个 method 里使用了 nake return,后面又注明 return value 。你说 block 了我 xttx,我用这个号回你。你这多看不出来么。 你强行打脸不成还去挖坟,你这个病得看。我也特别闲, 你挖坟得时候可以看看我的那个贴,错了就是错了。 <<为什么不要用 naked return>> https://levelup.gitconnected.com/go-naked-returns-4e2094b598e6?gi=5c972b7c406c https://www.ardanlabs.com/blog/2013/10/functions-and-naked-returns-in-go.html
lesismal
2021-10-06 00:05:30 +08:00
@XTTX 我针对的是你 #9 那句 “standard libs 都用一种方式是有原因的”,BTW 你看懂我引用的那几行代码是哪里的没。。。你仔细看下,那不是我自己代码,那个就是 go 源码,你所说的 std libs 不会是不包括 go 源码吧?
lesismal
2021-10-06 00:08:47 +08:00
“<<为什么不要用 naked return>>”

“standard libs 都用一种方式”
这两句话不是一回事好吗,我 #11 是回复 #9 楼这句的,麻烦少年看下

如果你不知道我引用的那几行是 go 源码,那当我没说吧
lesismal
2021-10-06 00:11:35 +08:00
源码都没怎么看,虽然不是什么过错,但是言之凿凿说源码这样子,对其他人会是一种误导。我是针对这个在杠。
我也早说过了,named 还是 naked,我自己都不用,也从没说过 named 或者 naked 是好东西。
lesismal
2021-10-06 00:14:49 +08:00
@XTTX #31 又是说 “所有的 std libs 都有明确的 return”。我引用那几行代码就是 go 源码,你看看有没有 named 和 naked 。如果说我之前错以为你没 at 人那一层是在回复我,那是我理解错了。但是我感觉我之前说的啥你也没看懂
XTTX
2021-10-06 09:19:07 +08:00
func (b *Reader) Discard(n int) (discarded int, err error) {
if n < 0 {
return 0, ErrNegativeCount
}
if n == 0 {
return
}

b.lastByte = -1
b.lastRuneSize = -1

remain := n
for {
skip := b.Buffered()
if skip == 0 {
b.fill()
skip = b.Buffered()
}
if skip > remain {
skip = remain
}
b.r += skip
remain -= skip
if remain == 0 {
return n, nil
}
if b.err != nil {
return n - remain, b.readErr()
}
}
}
XTTX
2021-10-06 09:32:16 +08:00
// ReadByte reads and returns a single byte.
// If no byte is available, returns an error.
func (b *Reader) ReadByte() (byte, error) {
b.lastRuneSize = -1
for b.r == b.w {
if b.err != nil {
return 0, b.readErr()
}
b.fill() // buffer is empty
}
c := b.buf[b.r]
b.r++
b.lastByte = int(c)
return c, nil
}


这两段来自同一个你引述的 package, 什么叫双重混用。这种代码读起来就不是非常舒服。你可以举证为什么这种代码是最优雅的。

"naked return 会影响 readability" 对我来说很明显,我不知道怎么解释。

我所有的回复都因为那个人的“我只知道 naked return”的半嘲讽,这个贴早就可以停了。你强行打脸,你打成了吗?其他人也应该少和你对话, 一言不合你就开始翻我的 post 记录,找找能人身攻击的东西,就差人肉了吧?其他人也回来翻翻你这个贴的行为

你说的那个贴,我真的不觉得有什么。我错了别人指出来,我认错,他还解释了我的提问。
lesismal
2021-10-06 10:23:18 +08:00
“这两段来自同一个你引述的 package, 什么叫双重混用。这种代码读起来就不是非常舒服。你可以举证为什么这种代码是最优雅的”
—— 所以你是真看不懂是吧。我上面说了,没有反驳这个是不是优雅。我针对的是,你说 std 里只有一种方式、std 里没有这种方式,而我引用的代码就是 std 里的、有这种方式。我上面都解释过了我也不觉得这样好,但不好跟没有是两码事,不要自己可能都没读过源码就随便说源码里没有。

“一言不合你就开始翻我的 post 记录,找找能人身攻击的东西,就差人肉了吧”
—— 上面也解释过了,是先看到你那个帖子里,又看到你这个帖子里,你对技术的观点太随意了。你可以再看下我 #29 楼中的第 2 条。

如果说前面是我自己以为你在回复我、算是我瞎,那后面回复了这些跳,解释了好几次,你没一次看懂了。另外,别提了另外个帖子就上纲上线的人身攻击转移话题,同为讨论技术的态度不严谨,要掰扯那正经点先把源码里有没有这种方式的事情扯清楚。我都强调过了那个就是源码、里面有这种方式、你都不正面回复又。反而我都强调过了我没说 named/naked 好,你也看到过了然后又来继续解释这个不好,我纠结它好不好了吗?
lesismal
2021-10-06 10:31:39 +08:00
1. “<<为什么不要用 naked return>>” —— 我没反驳过,我觉得这么说是 ok 的。
2. “standard libs 都用一种方式” —— 我反驳的是这个,因为源码里有这种方式,我引用的代码就是 go 源码

如果分不清我是在说 1 还是在说 2,那就停了吧。如果没读过 go 源码,甚至不知道 go 上面引用的就是 go 源码,那你随意吧。
lesismal
2021-10-06 11:18:27 +08:00
回到技术问题上,我也赞成 named/naked 不好,go 源码里虽然也有这样用,但仍然也不建议大家这样用。

go 源码有很适合用来学习,建议有兴趣的同学多读读。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/805771

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX