错误中的 %w 的位置

倾向于将%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