看到好多人吐槽 golang 的错误处理,但我用的很爽啊
golang 的错误处理,我之前也吐槽,但从 1.13 开始吧就挺好用了。 之前吐槽点:
- 如果底层函数出错,只在上层打印错误信息,会丢失调用栈,不知道最开始的错误发生在哪里。
- 如果通过字符串追加的方式,加入调用栈信息,那么错误类型会丢失,无法像 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]%sn", err.Error()) } else if err != nil { fmt.Printf("[error]:%sn", err.Error()) } fmt.Println(info) }