看到好多人吐槽 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)
}

9779 次点击
所在节点    Go 编程语言
74 条回复
no1xsyzy
2020-09-11 11:50:18 +08:00
看上去是类似反射的机制实现?
甚至写法上不如 C 宏优雅。
ZSeptember
2020-09-11 11:52:44 +08:00
写分布式或者一致性要求高的场景,Golang 的这种错误处理是很爽的。
每一步,都要考虑怎么处理,如果用异常,才是真正的反人类。
当然,写一般的业务代码,自然是异常爽,直接抛出去,在顶层捕获处理就可以了。
lance6716
2020-09-11 12:33:41 +08:00
抛异常不就是 panic 吗
yamasa
2020-09-11 14:51:57 +08:00
还是觉得 rust 那样的最优雅
pmispig
2020-09-11 14:54:03 +08:00
if err 没什么不爽 ,不爽的是需要错误信息自己手动拼接,层层上传,才能传到顶层
chengxiao
2020-09-11 15:03:36 +08:00
刚开始写的时候觉得很不爽,但是写久了突然不写了会感觉很慌.....怕漏错
kuro1
2020-09-11 15:06:03 +08:00
每一个 err 都处理,心智负担很小~
HiShan
2020-09-11 15:08:41 +08:00
看到好多人吐槽 Java 啰嗦,但我用的爽啊.
virusdefender
2020-09-11 15:09:47 +08:00
同样写的很爽,觉得虽然 if err != nil 确实有些繁琐,但是也还好。

最近写 lua,因为太容易出 bug 了,现在用 https://github.com/teal-language/tl/ 加一些自定义的类型,基本上和写 go 没啥区别了。
buffzty
2020-09-11 18:08:55 +08:00
C 语言不也是这样处理的吗? 那些吐槽的是没用过 c 吗?
monkeyWie
2020-09-11 18:35:32 +08:00
其实大多数情况下错误处理都是向外抛
```
err := case1()
if err!=nil{
return nil,err
}

err := case2()
if err!=nil{
return nil,err
}

doSome()
```
用 try catch 的话只用:
```
try{
case1()
case2()
doSome()
}catch(e){
throw e
}
```

这不是高下立判吗?
pisc
2020-09-11 19:13:25 +08:00
这东西就属于 taste 的问题,而 taste 的问题往往是因为见的少,大多数情况下,我不相信一个写习惯 Haskell (还有其他抽象程度足够高的语言)的人,会对 Go 的错误处理感到满意。
sagaxu
2020-09-11 19:20:55 +08:00
@monkeyWie 但是异常引入了其它问题

1. 构造析构函数里能不能抛,怎么处理
2. checked exception vs unchecked exception
3. finally 中修改了返回值,会不会生效
4. 性能问题,异常比返回值慢的多
5. 忘记处理异常,或者处理不当
blless
2020-09-11 20:00:27 +08:00
@monkeyWie 在 Java 里面其实也很容易无脑 catch 尤其是对新手,给程序埋下更大的隐患
dafsic
2020-09-11 20:38:43 +08:00
@monkeyWie 那我问一个问题,一个函数里需要字符串转整型的功能,如果字符串不是整数字符串,就当作 0 来处理怎么实现。现实中我有许多类似的需求,golang 实现如下:
```
func foo(index string) {
i, _ := strconv.Atoi(index)
// 忽略错误,继续处理,比如数据库某个字段默认是 0
}

```
用抛出异常的方式怎么实现?
Nugine0
2020-09-11 21:00:37 +08:00
rust 用问号运算符和异常差不多爽,要严格处理错误可以当场判断,能确保错误被处理,上下都涵盖了。
C 还能用宏,go 怎么偷懒?没法偷懒不就是反人类吗?
dafsic
2020-09-11 22:22:15 +08:00
@Nugine0 中宫飞出乾,次与兑艮连, 离坎接坤位,震循巽入中。
Nugine0
2020-09-11 22:33:23 +08:00
@dafsic ¿
sagaxu
2020-09-11 23:02:15 +08:00
@dafsic

"123".toIntOrNull() ?: 0
damngood
2020-09-11 23:06:47 +08:00
@pisc go 的 taste 比较另类点而已, 或者作者觉得直白够 simple 也是一种 good taste.

另外, 撇开 taste, 整体来说 go 用来做事情我个人还是比较满意的.

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

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

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

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

© 2021 V2EX