有了泛型,以前一直想做的 Go 错误处理终于可以实现了

2023-03-06 10:28:59 +08:00
 SuperMild

有些错误不需要特殊处理,就能用这些简单方便的函数,有错误就 panic, 无错误就直接返回有用结果:

func Try(err error) {
	if err != nil {
		panic(err)
	}
}

func Try1[V any](val V, err error) V {
	Try(err)
	return val
}

func Try2[V1 any, V2 any](val1 V1, val2 V2, err error) (V1, V2) {
	Try(err)
	return val1, val2
}

一个例子:

// 不使用泛型的传统实现
func GetExePath() string {
	path, err := os.Executable()
	if err != nil {
		panic(err)
	}
	return path
}
// 使用泛型,告别 `if err != nil`
func GetExePath() string {
	return Try1(os.Executable())
}
6766 次点击
所在节点    Go 编程语言
46 条回复
tangMu
2023-03-06 12:29:20 +08:00
然而,代码也越来越难读了
QlanQ
2023-03-06 13:07:17 +08:00
这样写,PHP 不香吗?

要么 PHP 随便抛,要么 rust ,必须 处理
gitxuzan
2023-03-06 13:15:57 +08:00
还有你定义错误的行数都不清楚,还是老老实实写吧,到了线上不是方便了,是找麻烦
darksword21
2023-03-06 13:36:26 +08:00
我不是很理解
raynor2011
2023-03-06 16:51:42 +08:00
https://github.com/samber/mo 这个库更符合 lz 的想法,这是一种函数式编程的设计模式,https://en.wikipedia.org/wiki/Monad_(functional_programming)
qza1212
2023-03-06 17:13:05 +08:00
这个就是装饰器啊,不推荐在装饰器里做异常处理,这样会导致装饰器有隐藏的顺序要求
lesismal
2023-03-06 17:50:23 +08:00
转 go 这些人哪,入乡随俗了解一下,非要越搞越蹩脚。。。
securityCoding
2023-03-06 21:01:06 +08:00
你是个高手 233 ,go 代码 panic oncall 工单不得搞死你
Hanggi
2023-03-06 21:09:42 +08:00
想了解下楼主用 Go 的原因是啥,明明思想上无法接受。

就好像手里攥着圣经敲木鱼一样,怎么看都是别扭
iseki
2023-03-06 21:21:08 +08:00
Go 的整个设计都让搞 try catch 极其困难
我只会在业务逻辑里 panic 而不 recover ,以 panic 为中断整个处理的方式
SuperMild
2023-03-06 22:18:15 +08:00
@Hanggi 我也很好奇,你为什么说我无法接受 Go 的语法?

if err != nil {panic(err)} 能处理错误,Must1(val, err) 也能处理错误,都符合 Go 的语法。

注意两点:

1. 看我的正文第一句话 “有些错误不需要特殊处理,就能用这些简单方便的函数”,我并没有说每一个错误都这样处理,只是有时候能偷懒,就这样偷懒,比如程序初始化阶段的一些很应该出错就崩溃的错误。

2. 我记得 Go 语言之父说过,error 就是一个普通的值,他建议大家用自己的方法写一些函数来处理这个值,怎么方便怎么来。
SuperMild
2023-03-06 22:24:36 +08:00
我不理解,上面很多人很鄙视用 panic 处理错误,意思是

A. 只要用了 panic, 就该被嘲笑,Go 语言就不该有 panic 这个函数。
B. 如果要用 panic, 就只能这样用 if err != nil {panic(err)},其他方法比如包裹一层 Must1(val, err) 就不行

究竟是 A 、B 哪个意思?
CC11001100
2023-03-07 00:02:44 +08:00
@SuperMild 生产环境中确实应该尽量避免 panic ,太容易背锅,用户可不 care let it crash 这一套,他只知道这玩意儿不能用了就投诉,完了就得背一个 P0 故障,锅背多了就得走人了。。。
SuperMild
2023-03-07 00:07:50 +08:00
@CC11001100 对呀,我也没说无脑一律 panic ,我第一句话说的就是 “有些错误不需要特殊处理,就能用这些简单方便的函数”,自己看情况用,另外我也附言给出了一个流行库,里面除了有 Must, 还有 TryOr 等多种不同的处理错误的方式,各有不同的使用场景。
dragonsunmoon
2023-03-07 00:21:25 +08:00
唉, 大道至简, go 的抽象表达能力就只能这样, 老老实实的一行代码,三行错误处理得了, 别整些其他语言的特性, 整出来的也是不伦不类.
SuperMild
2023-03-07 00:33:07 +08:00
@dragonsunmoon

以前没有泛型没办法,现在原本三行错误处理可以轻松简化为一行,为什么要“老老实实”?

也没有不伦不类啊,用的都是 Go 的最最基本的语法,仅仅非常简单地包裹了一层而已,这种包裹一下变成一个方便的函数的做法,不是日常编程的常规操作吗?
xuanbg
2023-03-07 02:37:43 +08:00
不要用 try catch 替代 if 来进行数据校验呀。try catch 也好,panic 也罢,这个习惯很不好的。
SuperMild
2023-03-07 08:41:38 +08:00
各位,不要执着于是否使用 panic, 重点应该是现在有了泛型,有些错误处理可以简化了,panic 只是其中一个例子而已,上面给出了 lo 和 mo 两个库,里面有 TryOr, Option 等多种方便的函数,根据需要选用。
dragonsunmoon
2023-03-07 11:01:25 +08:00
@SuperMild
探讨一些啊, 有几个问题

(1) go 官方给出的 error 处理的最佳实践是啥样的

(2) go 官方给出的泛型编程的最佳实践是啥样的

(3) 如果各个开源库都有一套自己的 error 处理方式, 那么在使用的时候会不会造成障碍, 会不会额外产生一些心智负担
SuperMild
2023-03-07 11:24:15 +08:00
@dragonsunmoon 刚好我也想更详细一点说说这个问题。

上面我提到 “我记得 Go 语言之父说过,error 就是一个普通的值,他建议大家用自己的方法写一些函数来处理这个值,怎么方便怎么来”

凭着记忆,我找到了来源。

先看这篇发表在 Go 官方博客,Rob Pike 写的文章 https://go.dev/blog/errors-are-values

拉到文章最后,他总结道:

> Use the language to simplify your error handling.
> But remember: Whatever you do, always check your errors!

意思是,建议大家灵活使用 Go 语言去简化错误处理,只要别漏掉错误就行。

===============

然后他推荐了一篇文章 https://jxck.hatenablog.com/entry/golang-error-handling-lesson-by-rob-pike

这篇文章是日英双语的,讲述了一个活动上,博客作者 jxck 对 Go 的错误处理有疑惑,受到 Rob Pike 指导的过程。

jxck 遇到了需要写大量 if err != nil {return err} 的情况,向 Rob Pike 请教,Rob Pike 当场就给他写了一个 Wrapper, 也就是包裹了一层,把 error 先集中记录下来,后续再一次性处理。

===============

因此,Rob Pike 写了那篇官方博客,标题就是 Errors are values ,意思是不要把错误处理看成什么特殊的事情,error 就是一个普通的值,你如何对待别的任何数值、变量,就如何对待 error, 大胆去用常规编程技巧处理它。

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

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

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

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

© 2021 V2EX