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

发布于 1周前 作者 bupafengyu 来自 Go语言

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

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 } 当作默认行为,不需要写这句就是这个行为,如果写了就覆盖默认行为。


更多关于Golang Go语言中据说2.0的错误处理有可能是这个样子的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

45 回复

再把 check 去掉就更好了

更多关于Golang Go语言中据说2.0的错误处理有可能是这个样子的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


那就是风格问题,不是好坏的问题。

一般应该在保持风格不变的前提下讨论,因为讨论风格很容易变成无意义的争吵。

这个方式很 golang ,不错

rust: 快来抄作业呀

这和老早的 try 的 proposal 不是一样的吗

要是能把 rust 的?实现那是极好的,怎么写怎么舒心

底下评论:

This version with check/handle is actually a rejected old draft which was reworked as try/defer, rejected again, and eventually gave the 1.13 error handling we now have.

珍惜 if (err != nil) 吧,这可是 Go 为数不多的 boilerplate 🐶

糟糕的设计。加了泛型以后 interface 已经支持 union type 了,弄个 Result 把 rust 的?抄过来就是。

这不是很早之前的 proposal 么



这个设计是兼容 Result 的,比如

<br>func foobar(a, b int) Result {<br> handle err { return NewResult(err) }<br>}<br>

如果彻底抛弃 error 改用 Result ,标准库以及第三方库就要全部重构了,显然是一个非常激进的决策,很难说比现在这个谨慎的决策更好吧。

后续如果社区越来越喜欢用 Result ,倒是再对 Result 提供特殊支持也不晚呀。

我之前没有专门去留意,今天看到 Medium Daily Digest 给我推荐才顺手点开看看。

可以暂时先留给第三方库去做,有了泛型之后自己包裹一个 Result 出来也行(想来应该会有人去做这个事,到时直接用就行)

不需要全部重构,双返回值到 Result 一个函数就可以解决。
x:=check(foo(a,b))?

又多出俩关键字来…能不能尽量用设计良好的语法和充分利用语法特性的标准库来实现,而不是想到什么就加点魔法…

当初没有设计完善就草草发布 1.0 版本的后遗症,只能走一步看一步,缝缝补补

这么快就背上历史包袱了

这是 2018 年的设计,早就被否了。

残废的类型系统导致很多东西没法用标准库扩展,只能开特权加魔法

诶…可 Go 好歹也算是个新语言啊,现在就这样了,以后可咋办啊…




Go 1 稳定了十年,现在 Go 2 大版本升级才加少量关键词,应该很正常吧?

Java 或 C# 之类的,大版本升级从未加过关键词吗?(而且,大版本升级加少量关键词在语言设计圈会被鄙视吗?感觉应该不至于是这样的风气才对。)

不是,只是感觉 go 里总是有很多奇怪的魔法,比如那个 make

原来如此,我刚才误会了。因为你说 “又多出俩关键字来”,后面又有人附和说 “只能开特权加魔法”,所以我误以为批判加关键词了。

至于 make ,确实不优雅,但 Go 的设计理念好像强调实用多过优雅,为了追求简化而放弃了很多东西,是一种选择,有得有失,我认为这个问题可以说喜欢或讨厌,却很难讨论对错。

这种设计看起来感觉还不如 unwrap 呢

if err != nil 写着也挺爽,简单粗暴,少记一个语法

是指 error 的 unwrap 方法吗?这个完全不影响 unwrap 的呀。

c/c++不也是用错误号吗,有啥不好的,我觉得现在错误处理就够用了

用 handler 比用 if 会更好吗? handler 里面不一样还是要用 if 写一堆判断?一个函数里面的内部需要返回不同的错误。

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

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

golang ,永远不太可能有除了 if err != nil { … } 之外的错误处理方案,因为它的设计哲学决定了这个。除非它改变设计哲学。像 Python 的做法是把错误当成异常,而不是值。

和泛型一起提出来的方案。。
像 Rust 那样 ? 不好吗
为了不承认自己设计错误,搞的大家的代码看起来那么恶心,写起来也恶心。
真是无语了

实在是想不通 try catch 到底 麻烦在哪了。



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


你的这个意见,上面已经有人提出了,而且我也回应过了,改成 ?,返回类型就变成了 Result ,几乎一切库都需要重构才能使用。目前这个方案已经可以非常方便地返回 Result ,后续可以看社区对 Result 的接受度再增加问号之类的语法糖支持。这是激进决策与谨慎决策的不同,只能说性格不一样,很难讨论对错。

可以兼容已有的库,只要最后一个返回值是 error ,就可以使用 ? 操作符。我知道社区早就讨论过这个方案了,也被拒绝了,在这里只是吐槽下,不能接受 Go Team 拒绝的理由而已。



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

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

而 Go 的方式,由于非常显性,提倡 “认真对待每一个 error”,因此按照 Go 的麻烦操作写出来的程序,通常会把可预见的 error 与不可预见的 panic 区分得非常清晰。

这个只能少数服从多数,现在有了泛型,Result 的基本用法已经可以用第三方库来实现,也肯定有人会去做这个库,但是看大家爱不爱用吧,如果非常多人爱用 Result ,应该会有语法糖支持。Go 团队一向很保守。



嗯,刚才突然想明白了,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 的东西。

写分布式应用的情况下,每个步骤的错误都需要仔细处理的时候就会觉得 try catch 很麻烦。go 的这种错误处理在这种场景下用起来还不错,但是写业务的时候,大部分中间步骤不需要处理,直接抛出,当然 try catch 很爽。
Result + ? 操作符,这两种情况场景处理起来的感觉都不错。

Go 的 error 对应的是 Java 的 checked exception ,和 Rust 的 Result<T, Err> 本质是一样的,只是用起来方不方便而已; Go 的 panic 对应的是 Java 的 runtime exception

一般有三种方式处理错误

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 的轮子。

我写了个 check 函数,日常一些不需要特殊处理的 error 就直接抛出。

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

貌似不少人都会自己写个类似的函数来粗暴处理,尤其是个人小项目。(当然,被说丑的时候还是无法反驳)

很难说 Go 这种实用主义是错的,就个人喜好上确实不太喜欢。不知道这样的实用主义会不会给后面带来麻烦呢

其实一直很好奇如何把异常当作常规控制流使用,比如递归时用一个 throw 结束递归?

有了泛型更好玩一点

啊,对哦!等泛型来了我就用这招。



举个例子,根据用户名查找用户帐号, 查无此人是正常逻辑,符合预期,一点也不 exception 。
某个订单里的用户 ID ,根据 ID 查找用户帐号,查无此人是 exception ,正常逻辑不应该走到这一步。

前面那个接口抛 UserNotFoundException 是滥用,后面那个合适。

哈哈哈,我到觉得既然是查找,那没有就是正常的,返回空就 OK 了。不过如果那个函数叫“修改用户信息”,这时候报用户找不到异常就是很合理的了~~~

x:=getx()?

还是问号更自然。

在Go语言社区中,关于Go 2.0错误处理的讨论一直是一个热门话题。虽然具体的实现细节尚未最终确定,但我们可以根据现有的提案和讨论来推测其可能的方向。

Go语言自1.0版本以来,一直以简洁和高效著称,但在错误处理方面,传统的if err != nil模式有时显得冗长且重复。因此,Go 2.0在错误处理上的改进可能会致力于简化这一流程,同时保持语言的清晰和一致性。

一种被广泛讨论的改进方案是引入一种更加结构化的错误处理方式,比如使用内置的try语句或者错误检查操作符。这些改进旨在减少代码中的重复和冗余,使错误处理更加直观和易于维护。

然而,任何对Go语言的重大更改都需要谨慎考虑,以确保不会破坏现有的代码库或引入不必要的复杂性。因此,Go团队在推进这些更改时,会充分考虑社区的意见和反馈,以确保最终的设计既符合Go语言的哲学,又能满足开发者的实际需求。

总的来说,虽然Go 2.0的错误处理具体会是什么样子还不得而知,但我们可以期待它会在保持Go语言简洁性的同时,提供更加灵活和强大的错误处理机制。作为开发者,我们可以关注Go语言的官方提案和讨论,以便及时了解这些更改的最新进展。

回到顶部