据说 Go 2.0 的错误处理有可能是这个样子

2022-01-22 11:05:44 +08:00
 SuperMild
func foobar(a, b int) error {
    handle err { return err } // This is our handler
    x := check foo(a, b) // check invokes the handle func
    y := check bar(a, b) // this on as well
}

看起来还蛮好的。

来源: https://levelup.gitconnected.com/golang-2-0-draft-feature-error-handling-c0a2332b9162

但我觉得还能改进,比如把 handle err { return err } 当作默认行为,不需要写这句就是这个行为,如果写了就覆盖默认行为。

5848 次点击
所在节点    Go 编程语言
44 条回复
iseki
2022-01-22 13:02:44 +08:00
@SuperMild 不是,只是感觉 go 里总是有很多奇怪的魔法,比如那个 make
SuperMild
2022-01-22 13:24:28 +08:00
@iseki 原来如此,我刚才误会了。因为你说 “又多出俩关键字来”,后面又有人附和说 “只能开特权加魔法”,所以我误以为批判加关键词了。

至于 make ,确实不优雅,但 Go 的设计理念好像强调实用多过优雅,为了追求简化而放弃了很多东西,是一种选择,有得有失,我认为这个问题可以说喜欢或讨厌,却很难讨论对错。
dotmeow
2022-01-22 13:43:38 +08:00
这种设计看起来感觉还不如 unwrap 呢
Zwying
2022-01-22 13:45:58 +08:00
bad design
KousukeSakurako
2022-01-22 13:49:16 +08:00
if err != nil 写着也挺爽,简单粗暴,少记一个语法
SuperMild
2022-01-22 13:53:36 +08:00
@dotmeow 是指 error 的 unwrap 方法吗?这个完全不影响 unwrap 的呀。
darknoll
2022-01-22 14:09:31 +08:00
c/c++不也是用错误号吗,有啥不好的,我觉得现在错误处理就够用了
anonymous256
2022-01-22 16:44:10 +08:00
用 handler 比用 if 会更好吗? handler 里面不一样还是要用 if 写一堆判断?一个函数里面的内部需要返回不同的错误。

这个草案是不可能被通过的。
因为这违背了 Golang 的基本设计哲学:错误是值。
https://go.dev/blog/errors-are-values

不直接去返回那个(错误的)值,却放在 handler 里面去返回,不是在搞笑吗?这会让你同一逻辑的代码在空间上分离。比如一个函数 和它的错误处理在代码的空间上分离,这绝对更加不利于代码的可读性。if err != nil { ... } 只是丑陋了一点,但是可读性仍然是良好的。

golang ,永远不太可能有除了 if err != nil { ... } 之外的错误处理方案,因为它的设计哲学决定了这个。除非它改变设计哲学。像 Python 的做法是把错误当成异常,而不是值。
ZSeptember
2022-01-22 17:22:30 +08:00
和泛型一起提出来的方案。。
像 Rust 那样 ? 不好吗
为了不承认自己设计错误,搞的大家的代码看起来那么恶心,写起来也恶心。
真是无语了
Joker123456789
2022-01-22 17:35:22 +08:00
实在是想不通 try catch 到底 麻烦在哪了。
SuperMild
2022-01-22 17:44:55 +08:00
@anonymous256

1. 返回值这一点没有变,新语法还是返回值。
2. 错误处理在代码的空间上分离,专门用一个 handleErr 函数来处理错误,非常常见,Go 的 web 框架 Echo 就是这样做的。


@ZSeptember 你的这个意见,上面已经有人提出了,而且我也回应过了,改成 ?,返回类型就变成了 Result ,几乎一切库都需要重构才能使用。目前这个方案已经可以非常方便地返回 Result ,后续可以看社区对 Result 的接受度再增加问号之类的语法糖支持。这是激进决策与谨慎决策的不同,只能说性格不一样,很难讨论对错。
ZSeptember
2022-01-22 17:51:54 +08:00
@SuperMild 可以兼容已有的库,只要最后一个返回值是 error ,就可以使用 ? 操作符。我知道社区早就讨论过这个方案了,也被拒绝了,在这里只是吐槽下,不能接受 Go Team 拒绝的理由而已。
SuperMild
2022-01-22 17:53:39 +08:00
@Joker123456789

try catch 据说运行效率比较低。

在使用上,try catch 通常更方便,但 try catch 的思想是 “实在有需要的时候才处理错误”,因此通常会留很多错误让它崩。

而 Go 的方式,由于非常显性,提倡 “认真对待每一个 error”,因此按照 Go 的麻烦操作写出来的程序,通常会把可预见的 error 与不可预见的 panic 区分得非常清晰。
SuperMild
2022-01-22 17:57:53 +08:00
@ZSeptember 这个只能少数服从多数,现在有了泛型,Result 的基本用法已经可以用第三方库来实现,也肯定有人会去做这个库,但是看大家爱不爱用吧,如果非常多人爱用 Result ,应该会有语法糖支持。Go 团队一向很保守。
Joker123456789
2022-01-22 18:02:43 +08:00
@SuperMild

嗯,刚才突然想明白了,go 的 error 就不能把他当异常处理,只能当做是一种 代码健壮性的手段,其实任何语言都有这种东西的,只不过没有专门提供一个 error 类型。

比如:

js

function test(param){
if (param == null){
return "参数不可以为空";
}
}

java

public String test(String param){
if (param == null){
return "参数不可以为空";
}
}


真正用来做异常处理的 应该是 panic + recover + 析构函数,他才是对标其他语言里 try catch 的东西。
ZSeptember
2022-01-22 18:19:33 +08:00
@Joker123456789 写分布式应用的情况下,每个步骤的错误都需要仔细处理的时候就会觉得 try catch 很麻烦。go 的这种错误处理在这种场景下用起来还不错,但是写业务的时候,大部分中间步骤不需要处理,直接抛出,当然 try catch 很爽。
Result + ? 操作符,这两种情况场景处理起来的感觉都不错。

Go 的 error 对应的是 Java 的 checked exception ,和 Rust 的 Result<T, Err> 本质是一样的,只是用起来方不方便而已; Go 的 panic 对应的是 Java 的 runtime exception
sagaxu
2022-01-22 18:22:32 +08:00
一般有三种方式处理错误

1. 返回值中携带错误码,先检查错误码再决定是否使用返回值
2. 传入一个 code 指针,函数体中修改这个 code
3. try-catch-finally 一把梭

方案 1 ,每次调用都要创建一个包裹 code 的对象实例,多个对象多个开销,内存布局优化的好的语言不惧包裹对象的开销。Go 选择了多返回值,没有包裹对象,因此开销也不大。

方案 2 ,不支持指针的语言不合适,传一个对象进去,修改其 field ,对性能优化有更高的挑战。

方案 3 ,在 exception 没有实际发生的时候,try 中的代码性能损失很小,可能会影响一些优化,但整体可控。而一旦 exception 发生,性能下降几个数量级,所以只能作为异常使用,不能作为代码流程控制的手段。

方案 3 的优势是 exception 可以冒泡,一层层往上传递,比如 web 框架,可以在 handler 中统一 catch 和记录,特立独行的 go 把这个叫做 pannic-recover ,可能是个比较方的 try-catch-finally 的轮子。
SuperMild
2022-01-22 18:26:51 +08:00
@ZSeptember 我写了个 check 函数,日常一些不需要特殊处理的 error 就直接抛出。

func check(err error) { if err { panic(err)} }

貌似不少人都会自己写个类似的函数来粗暴处理,尤其是个人小项目。(当然,被说丑的时候还是无法反驳)
iseki
2022-01-22 18:44:28 +08:00
@SuperMild 很难说 Go 这种实用主义是错的,就个人喜好上确实不太喜欢。不知道这样的实用主义会不会给后面带来麻烦呢

@sagaxu 其实一直很好奇如何把异常当作常规控制流使用,比如递归时用一个 throw 结束递归?
ZSeptember
2022-01-22 18:51:31 +08:00
@SuperMild 有了泛型更好玩一点

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

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

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

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

© 2021 V2EX