if err != nil {
// Return an error which unwraps to err.
return fmt.Errorf("pack %v: %w", name, err)
}
需要区分%w和%v的地方:
读取代码块中的注解 *
f, err := os.Open(filename)
if err != nil {
// The *os.PathError returned by os.Open is an internal detail.
// To avoid exposing it to the caller, repackage it as a new
// error with the same text.
//
//
// We use the %v formatting verb, since
// %w would permit the caller to unwrap the original *os.PathError.
return fmt.Errorf("%v", err)
}
2条答案
按热度按时间66bbxpm51#
我应该使用%s或%v来格式化错误吗?
**TL;DR;**两者都不是。在99.99%的情况下使用
%w
。在其余0.001%的情况下,%v
和%s
可能“应该”具有相同的行为,但错误值为nil
时除外。%v
对nil
错误的友好输出可能是首选%v
的原因(见下文)。详情如下:
使用
%w
代替%v
或%s
:从Go语言1.13开始(如果使用golang.org/x/xerrors的话,可以使用
%w
动词,但只能用于error
值,它会将错误 Package 起来,以便以后可以用errors.Unwrap
来展开,也可以用errors.Is
和errors.As
来考虑。唯一不合适的情况是:
1.您必须支持旧版本的Go语言,并且
xerrors
不是一个选项。1.您希望创建一个唯一的错误,而 * 不 * Package 一个现有的错误。这可能是合适的,例如,如果您在搜索用户时从数据库中得到一个
Not found
错误,并希望将其转换为Unauthorized
响应。在这种情况下,您很少会使用带有 any 格式动词的原始错误值。好的,那么
%v
和%s
又是怎么回事呢?%s
和%v
是如何实现的细节可以在文档中找到,我已经突出显示了与您的问题相关的部分。1.如果操作数是一个reflect.Value,则操作数将被它所保存的具体值替换,并且打印将继续下一个规则。
1.**如果操作数实现了Formatter接口,则将调用该接口。**Formatter提供了对格式设置的精细控制。
1.如果%v动词与# flag(%#v)一起使用,并且操作数实现了GoStringer接口,则将调用该接口。
如果格式(对于Println等,隐式为%v)对字符串(%s %q %v %x %X)有效,则应用以下两个规则:
1.如果操作数实现了error接口,则会调用Error方法将对象转换为字符串,然后根据 predicate (如果有)的要求格式化字符串。
1.如果操作数实现了String()string方法,则会调用该方法将对象转换为字符串,然后根据 predicate (如果有)的要求格式化字符串。
总之,
fmt.*f
函数将:1.查找
Format()
方法,如果它存在,则调用它。1.查找
Error()
方法,如果它存在,则调用它。1.查找
String()
方法,如果它存在,就调用它。1.使用一些默认格式。
因此,实际上,这意味着
%s
和%v
是相同的,除非错误类型上存在Format()
方法(或者当错误是nil
时)。当错误确实有Format()
方法时,可能希望它会产生与%s
、%v
和err.Error()
相同的输出。但由于这取决于错误的实现,因此没有任何保证,因此这里没有“正确答案”。最后,如果您的错误类型支持
%+v
动词变体,那么如果您需要详细的输出,当然需要使用它。nil
个值虽然很少(有意地)在
nil
错误时调用fmt.*f
,但%s
和%v
的行为确实不同:Playground link
628mspwn2#
使用
%v
作为误差值。但是,在
Go 1.13
中,fmt.Errorf
函数支持一个新的%w
predicate 。当此 predicate 存在时,fmt.Errorf
返回的错误将使Unwrap
方法返回%w
的参数,这肯定是一个错误。在所有其他方面,%w
与%v
相同。需要区分
%w
和%v
的地方:Read:对于错误,何时应该切换到w
此外,内置的error接口允许Go语言程序员添加任何他们想要的信息,它只需要一个实现
Error
方法的类型示例:
因此,大多数示例都具有类似的实现类型,其中
err
具有Error
方法,该方法返回string
,您可以使用%s
对其进行处理