go 有没有比较合适的异常处理流程方案

2022-07-09 19:29:54 +08:00
 pkupyx

新转 go ,发现接的项目的错误都是这种模式,并且出现次数极多: data, err:= xxx.xxx if err != nil { log.xxx return xxx,err }

有没有 java 那种,只要在业务逻辑里面: throw XxxException

然后在最外层有一个统一的方法拦截全部 RuntimeException 的方式来处理异常流的方法么? exceptionHandler(XxxException xxx){ ... }

2873 次点击
所在节点    程序员
24 条回复
BugCry
2022-07-09 19:32:16 +08:00
panic/recover 。但是用 Java 的思维写 go ,为什么不直接写 Java ?
golangLover
2022-07-09 19:34:41 +08:00
不用想了,没有,问就是大道至简
golangLover
2022-07-09 19:35:49 +08:00
对了,除了大道至简,还有招人上手容易,一两天就能写代码。
Trim21
2022-07-09 19:37:25 +08:00
panic/recover (
wangx0102
2022-07-09 19:38:37 +08:00
感觉就 panic/recover
LukeEuler
2022-07-09 19:50:58 +08:00
https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md

官方很早就在思考并设计这块内容了,至于什么时候来,就不知道了。我个人更喜欢 rust 的设计。
iyaozhen
2022-07-09 21:36:52 +08:00
没有,写 Go 千万不要和 Java 对比,完全不是一个阶段。
frodez
2022-07-09 21:43:26 +08:00
虽说我日常看不惯 go ,但我仍然要问:你为什么需要一个统一的错误处理逻辑?你真的想清楚了原因,而非一时偷懒选择了它?

你或许应该了解到,和错误处理相关的问题永远都包括两个议题:如何正确处理错误,和如何方便地处理错误。但很可惜绝大多数人都混淆了它们,并把它们视为同一个问题。
frodez
2022-07-09 21:48:41 +08:00
另外,方便地处理错误往往会让程序员有精力正确地处理错误,但不是说方便地处理错误就会让程序员一定能正确地处理错误。另一方面,正确地处理错误在某种程度上可以让错误处理更方便,但跨过了某个分界点后,正确处理错误又不能与方便地处理错误相妥协。所以这必须是一个与实际业务紧密相关的问题,如果不相关,那么你的做法就会既不方便也不正确。
pkupyx
2022-07-09 21:50:39 +08:00
@frodez 因为服务端业务代码 95%以上的 err 只需要封装到统一结构然后层层传给调用方。
frodez
2022-07-09 21:57:13 +08:00
@pkupyx 我个人的建议仍然是优先选择正确性。如果真的可以把错误归类为 95%的不需要自己处理的错误,和 5%的需要自己处理的错误,你可以把前者和后者分开,前者一路返回,后者自己专门处理。

不是非常建议使用 panic 和 recover ,因为它们都是函数级别的跳转逻辑——如果你要在循环中处理错误,使用 panic 和 recover 很可能会导致遗漏。
iseki
2022-07-09 22:08:23 +08:00
panic 吧,一般可以用这种方法处理的错误,都不是真的能处理的错误,panic 最方便了
kidlj
2022-07-09 22:14:17 +08:00
写 web 的话,echo 框架有集中处理错误的方式,比如加上 message 字段或者根据 accept header 返回不同的 content-type 数据。在业务 handler 里只需要 return error 就好了。

另外,同意楼上说的,方便的不一定是正确的。Go 的错误处理虽然还有优化空间,但在很多人看来这种方式起码是正确的。
hallDrawnel
2022-07-10 00:31:32 +08:00
正确的做法就是就地判断 error ,当场决定是否要处理。相比抛出异常,有了更合理的处理时机——在错误发生的地方,持有错误发生的上下文信息,可以自由地编写针对性的处理逻辑;而统一的异常处理节点已经丢失了错误发生的上下文信息。赞同 frodez 的说法,统一的逻辑往往就会变得既不方便也不正确。

panic 仅仅应该用在整个程序已经无法继续运行的时候,对于业务逻辑来说很少有这种情况。
joesonw
2022-07-10 00:32:59 +08:00
@pkupyx err 往上传就是为了在每一层调用的地方加上现场信息,方便查询错误在哪。
无脑往上抛要还原现场就只能抓 stacktrace 了,这样的运行时成本就高了。你要不在乎这个性能损失的话无脑 panic 也是可以的,最外层 recover 抓个 stacktrace 。例如一众 web 框架里面都会有的 Recover 的 middleware 。
LeslieWongH
2022-07-10 10:59:08 +08:00
插一句,JS 的 try catch 异步函数的替代方案就是模仿 go 的思路,返回[err, data]数组——
参见 NPM 仓库 await-to-js
pkupyx
2022-07-10 15:40:53 +08:00
@joesonw 然而绝大多数场景就是只有在错误发生的位置抓 stacktrace ,其他层级无脑往上抛。
比如常见的一个服务的调用,展开之后是这个结构:

handler.getCompanyAdminList(companyId) (list, err) {
// 封装了校验和调用 service
// ...
list, err := service.getCompanyAdmin( companyId ) (list, err) {
// 封装了获取 admin 和拼接 admin 权限
// ...
list, err := adminRepo.getCompanyAdmin() (list, err) {
// 封装了取 cache 和 orm
// ...
list, err := orm.getCompanyAdmin() {
// 封装 db
list, err := db.select()
if err!=nil { 1
// log
return nil, err
}
}
if err!=nil { 2
return nil, err
}
// ...
// 其他业务代码
}
if err!=nil { 3
return nil, err
}
// ...
// 其他业务代码
}
if err!=nil { 4
return nil, err
}
// ...
// 其他业务代码
}

只有 1 需要 log ,然后抛出错误到最外层,根据错误直接返回 response 。2 、3 、4 步骤就是无脑略过。
mekingname
2022-07-11 09:42:04 +08:00
无脑略过的 err ,可以直接用_代替啊。

data, _ = 函数()

也不需要用 if 去判断。
partystart
2022-07-11 10:15:54 +08:00
@mekingname

如果 data 是指针类型,你用下划线忽略。 你怎么处理?

如果 data == null 就返回? 万一下游 API 调用正常但是无数据也返回空指针呢?
mekingname
2022-07-11 12:14:25 +08:00
@partystart 我忽略的是 err ,又没有忽略 data

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

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

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

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

© 2021 V2EX