倾向于将%w
放在错误字符串的末尾。
错误可以用%w
动词来包装,或者把它们放在一个实现Unwrap()错误
的结构化错误中(例如:fs.PathError
)。
被包裹的错误形成错误链:每一层新的包裹都会在错误链的前面增加一个新的条目。错误链可以用Unwrap()error
方法进行遍历。比如说:
err1 := fmt.Errorf("err1")err2 := fmt.Errorf("err2: %w", err1)err3 := fmt.Errorf("err3: %w", err2)
这就形成了一个错误链的形式,
flowchart LR err3 == err3 wraps err2 ==> err2; err2 == err2 wraps err1 ==> err1;
不管%w
动词放在哪里,返回的错误总是代表错误链的前面,而%w
是下一个子节点。同样,Unwrap()error
总是从最新的错误到最旧的错误穿越错误链。
然而,%w
动词的位置会影响错误链是从最新到最旧,从最旧到最新,还是两者都不影响:
// Good:err1 := fmt.Errorf("err1")err2 := fmt.Errorf("err2: %w", err1)err3 := fmt.Errorf("err3: %w", err2)fmt.Println(err3) // err3: err2: err1// err3 is a newest-to-oldest error chain, that prints newest-to-oldest.
// Bad:err1 := fmt.Errorf("err1")err2 := fmt.Errorf("%w: err2", err1)err3 := fmt.Errorf("%w: err3", err2)fmt.Println(err3) // err1: err2: err3// err3 is a newest-to-oldest error chain, that prints oldest-to-newest.
// Bad:err1 := fmt.Errorf("err1")err2 := fmt.Errorf("err2-1 %w err2-2", err1)err3 := fmt.Errorf("err3-1 %w err3-2", err2)fmt.Println(err3) // err3-1 err2-1 err1 err2-2 err3-2// err3 is a newest-to-oldest error chain, that neither prints newest-to-oldest// nor oldest-to-newest.
因此,为了使错误文本反映错误链结构,最好将%w
动词放在最后,形式为[...]: %w
。