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

10457 次点击
所在节点    Go 编程语言
74 条回复
reus
2020-09-12 17:12:06 +08:00
@dafsic 我看你这个“普遍写法”是要爆大锅,你以为是 0,实际输入如果超出 64 位整数能表示的范围,那它返回的是最大可以表示的整数,如果这个返回值用在循环里,你的程序就要跑很久很久了。所以错误最好不要忽略,也不要认为返回错误时,其他返回值就是零值。很简单的例子,io.Reader.Read,返回 io.EOF 时,另一个返回值也可能非零。
treblex
2020-09-12 18:18:51 +08:00
工具类直接 panic,在外层逻辑使用 defer recover
最近学到这个用法,看起来会比较干净
monkeyWie
2020-09-12 18:35:56 +08:00
@dafsic #55 👨‍🦳笑了,谁跟你说的 err 返回了就一定返回 0,编译器的约定吗?
herozzm
2020-09-12 18:54:07 +08:00
比 try 好用
dafsic
2020-09-12 19:11:58 +08:00
@monkeyWie 行啦,不回复你了,有时间多学学习吧
monkeyWie
2020-09-12 19:28:22 +08:00
@dafsic 不是,60 61 楼打脸了就不回了?还有希望你提高点姿势水平,跟你不在一层讨论的没意义,后面我也不会回复了
xcp3555
2020-09-12 21:06:47 +08:00
看起来不太爽
dafsic
2020-09-12 22:22:28 +08:00
@reus 确实是,我这样写了三年多,运气好没遇到问题。至于错误忽略不忽略看信任边界了。
gamexg
2020-09-12 22:40:32 +08:00
没用前觉得到处是 if err!=ni 不想用。
真用了才发现这个比异常更可靠,使用异常时经常对一大块代码一个 try 完事;但是用了 go 的 err 后,会对每个 可能出错的地方进行检查,更加仔细了。

打起来麻烦及显示占空间的问题,goland ide 本身会进行处理。
davichi2009
2020-09-14 09:07:03 +08:00
@dafsic 转之前不先判断参数类型? 类型转换的操作任何时候都要先判断类型的吧? 类型不匹配返回一个指定的默认值不就可以了?
flywheel
2020-09-18 11:06:35 +08:00
不做特殊处理,方便理解及代码阅读
sutra
2020-09-21 09:50:47 +08:00
满屏 if err !=nil 很是酸爽。
simenet
2020-09-22 11:31:49 +08:00
很希望多一个 try 就不用写一大堆 err!=nil 了
zunceng
2020-09-28 14:27:44 +08:00
上面一口一个 try catch 的 不用看你们的代码 我就知道充满各种错误

简单来说
如果说 if err != nil 的问题是丑
try catch 的问题就是没法写出对的代码

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

https://ex.noerr.eu.org/t/706008

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

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

© 2021 V2EX