看到好多人吐槽 golang 的错误处理,但我用的很爽啊

2020-09-11 09:22:06 +08:00
 dafsic

golang 的错误处理,我之前也吐槽,但从 1.13 开始吧就挺好用了。 之前吐槽点:

  1. 如果底层函数出错,只在上层打印错误信息,会丢失调用栈,不知道最开始的错误发生在哪里。
  2. 如果通过字符串追加的方式,加入调用栈信息,那么错误类型会丢失,无法像 if err == io.EOF 这样判断是什么错误。

现在已经不是问题了。

// LineInfo 返回调用此函数的代码所在函数、文件、行号
// 此函数应该在一个单独的文件中,比如,utils/getlineinfo.go
func LineInfo() string {
	function := "xxx"
	pc, file, line, ok := runtime.Caller(1)
	if !ok {
		file = "???"
		line = 0
	}
	function = runtime.FuncForPC(pc).Name()
	return fmt.Sprintf(" -> %s():%s:%d", function, file, line)
}

var ErrAuth = errors.New("auth error")
var ErrAccount = fmt.Errorf("%w: account not exist", ErrAuth)
var ErrPassword = fmt.Errorf("%w: incorrect password", ErrAuth)

func login(acc, pwd string) (string, error) {
	if acc != "libai" {
		return "", ErrAccount
	}
	if pwd != "123456" {
		return "", ErrPassword
	}

	return fmt.Sprintf("key:AC34cvG-%d", time.Now().Unix()), nil
}

func getInfo(acc, pwd string) (string, error) {
	key, err := login(acc, pwd)
	if err != nil { // login 的错误
		return "", fmt.Errorf("%w%s", err, LineInfo())
	}

	// 打开下面的注释就会是 key 过期
	//time.Sleep(time.Second)

	msg, err := getIntro(key)
	if err != nil { // key 错误
		return "", fmt.Errorf("%w%s", err, LineInfo())
	}

	return msg, nil
}

var ErrKey = errors.New("invalid key")

func getIntro(key string) (string, error) {
	if key != fmt.Sprintf("key:AC34cvG-%d", time.Now().Unix()) {
		return "", ErrKey
	}

	return "李白,号青莲居士", nil
}

func main() {
	info, err := getInfo("libai", "123456")
	if err != nil && errors.Is(err, ErrAuth) { // 无论账号错误还是密码错误,都是认证错误
		fmt.Printf("[info]%s\n", err.Error())
	} else if err != nil {
		fmt.Printf("[error]:%s\n", err.Error())
	}

	fmt.Println(info)
}

9796 次点击
所在节点    Go 编程语言
74 条回复
crclz
2020-09-11 23:12:26 +08:00
golang 错误处理适合一般的团队,团队成员层次不齐的情况下依然保证不会在错误处理上面出重大问题。
java 异常会被参差不齐的开发人员滥用。所以,只有那些真正理解异常并正确使用异常的人,才有权利说 java 异常用得爽、go 的繁琐。
Jirajine
2020-09-11 23:13:56 +08:00
@cmdOptionKana golang 槽点太少?你怎么好意思说。
错误处理、泛型、duck typing 、编译时不严格检查、零值初始化、关键词过度复用、unused variable/import 该是 warning 非要当 error,等等。网络上成千上万字批判 go 的文章一大堆。
wamson
2020-09-11 23:38:00 +08:00
写过一个月 go,还是没 python 写得爽,弃了,要性能的话我就写 cpp,再用 py 调吧
pisc
2020-09-11 23:39:57 +08:00
@damngood 你说你觉得满意没问题,毕竟人嘛自己自己看着舒服最重要,但它哪里称得上“另类”?这玩意儿除了突出一个简单无脑,我看不出有另类的地方,拿 product type 来表现天然 union 结构的东西,如果这也算是 good taste 的话。。。
damngood
2020-09-12 00:12:30 +08:00
@pisc 我意思是作者从另外一个角度去看待你说的 taste, 或许他们认为这种 c 类似的方式比较简单直白所以算 good taste? 毕竟 go 的口号之一就是 simple and straight.

另外 taste 这个东西和别的东西权衡下来或许也没有那么重要? 当然如果有种完美语言又有 taste 又工程性很高有简单上手, 那当然是最好不过了. 不过目前看下来 swift 个各方面权衡不错的, 只不过框在 apple 的生态了, 其他领域还远着...
chenqh
2020-09-12 01:29:14 +08:00
@dafsic 如果是 python
try:
v = int(param_str)
except ValueError:
v = 0
return 0
nuk
2020-09-12 02:43:32 +08:00
除了没有调用栈,唯一的缺点就是有点麻烦
一般 if err !=nil 在我写的 go 里面要占一半左右
曾经我也觉得没有调用栈调试会比较麻烦
不过事实证明只要 error 写的够详细
基本上错误打印出来就能大概知道怎么发生的了
jiangzm
2020-09-12 03:35:37 +08:00
同样是 google 开发的编程语言,dart 比 golang 看着顺眼多了
因为要维护一个 golang 项目,学了点皮毛,给我的感觉是 golang 在语言特性方面为了区别而区别,看着不伦不类的感觉。
不过对于 go 主力开发人员来说看多了应该也习惯了
YzSama
2020-09-12 10:20:42 +08:00
@HiShan #28 有一说一,我也觉得 Java 异常处理也很爽。

不过,我觉得 Go 的异常处理机制,既然现在可以判断异常类型。那为啥不能统一处理。
kneep
2020-09-12 11:03:51 +08:00
官方邮件列表里面也经常有人提议各种简化 if err != nil 等样板代码的方案
darknoll
2020-09-12 11:21:59 +08:00
我也不喜欢用异常啥的
linvaux
2020-09-12 12:07:29 +08:00
之前我不能理解为啥一定要返回 err,后来就习惯了,无所谓咯,go 人家就这么设计的,爱用不用
monkeyWie
2020-09-12 14:15:01 +08:00
@dafsic #35 这个很简单啊
```
int i;
try{
i = Integer.valueof(index)
}catch(NumberFormatException e){
i = 0;
}
```
monkeyWie
2020-09-12 14:19:56 +08:00
@dafsic #35 而且你给的这个例子就奇怪,都没做错误处理,正确的写法不应该是这样吗:
```
func foo(index string) {
i, err := strconv.Atoi(index)
if err!=nil{
i = 0
}
}

```
因为不能保证这个方法在有 err 返回的时候,第一个返回值的就一定是你想要的 0 。
dafsic
2020-09-12 15:34:05 +08:00
@monkeyWie 只能说你根本就不会用 golang,哪怕写过一个月的 golang 也知道我写的就是普遍写法。
dafsic
2020-09-12 15:38:49 +08:00
@chenqh golang 只需忽略错误即可,返回值默认是零值。
dafsic
2020-09-12 15:45:41 +08:00
@Nugine0 奇门遁甲九宫飞泊口诀
dafsic
2020-09-12 15:50:01 +08:00
@wamson 写过半年 Python,写的确实爽,读起来,维护起来能要命,全靠注释。
Nugine0
2020-09-12 17:03:30 +08:00
@dafsic 这和编程语言有什么关系?
reus
2020-09-12 17:06:34 +08:00
@dafsic 错,你看看 strconv.ParseInt 的文档就知道了。或者跑下这个程序,看看返回是不是 0 ? https://play.golang.org/p/0dLcyPJFt32

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

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

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

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

© 2021 V2EX