Created: 15 Nov 2022
Last modified: 26 Mar 2023
Golang-error-type
演示代码
先模拟一个在写业务代码时常见的方法 GetDatabase
,其会根据 flag 参数决定是否返回数据或空指针和 error。
接着的 Client
函数代表一些常规的业务处理逻辑,如当你指定的查询层级小于数据库值时返回 internalError,或者层级小于等于一触发某网络故障。
package main import ( "errors" "fmt" "os" ) var ( ThirdPartyError = errors.New("third party error") InternalError = errors.New("internal error") ) func main() { data, err := Client(100) handleError(err) echoData(data) data, err = Client(0) handleError(err) echoData(data) data, err = Client(5) handleError(err) echoData(data) } func GetDatabase(errorFlag bool) (*int, error) { if errorFlag { return nil, fmt.Errorf("connection reset by peer") } var res = 10 return &res, nil } func Client(level int) (int, error) { flag := false if level <= 1 { flag = true } ptr, err := GetDatabase(flag) if err != nil { hint := err.Error() return 0, fmt.Errorf("%s: %w", hint, ThirdPartyError) } if level < *ptr { return 0, fmt.Errorf("data is less than 10 %w", InternalError) } return *ptr, nil } func handleError(err error) { if err == nil { return } if errors.Is(err, ThirdPartyError) { fmt.Printf("match cmdb error: %v\n", err) return } if errors.Is(err, InternalError) { fmt.Printf("match internal error: %v\n", err) os.Exit(1) } } func echoData(d int) { fmt.Printf("got data: %d\n", d) }
创建故障变量
由 errors.New(string)
根据指定参数创建,即返回了一个实现了 error interface 的对象。
注意,多次调用产生的都是不同变量,故多次即为不同值。
// New returns an error that formats as the given text. // Each call to New returns a distinct error value even if the text is identical. func New(text string) error { return &errorString{text} } // errorString is a trivial implementation of error. type errorString struct { s string } func (e *errorString) Error() string { return e.s }
故障包装
当在客户端调用访问数据库接口后,会结合方法返回值和业务逻辑通过 fmt.Errorf()
的 %w
动词来进行包装:
- 方法出现如网络错误时
fmt.Errorf("%s: %w", hint, ThirdPartyError)
包装三方错误; - 与内部逻辑冲突时,包装 InternalError 告知上游函数;
解包装
先想想一常见情景,当不使用 errors
包时,我们可区分外部或内部故障的方法有匹配 err.Error()
字符串,但该匹配字符串的方法耦合程度较高。
而使用 errors.Is
可无需过分关注 err string 成员值, Is
会在当前 err 的包装链上逐个查找。
// Is reports whether any error in err's chain matches target. // // The chain consists of err itself followed by the sequence of errors obtained by // repeatedly calling Unwrap. func Is(err, target error) bool
renyddd by Renyddd is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.