%s
%v
and %w
可用于格式化 Go 中的错误(将它们转换为字符串)fmt.Errorf
).
它们在 Go 自己的工具中的使用方式似乎有所不同。
In cmd/go/internal/get/path.go https://github.com/golang/go/blob/1fb7d5472e8f46faaa034fe6e16ca66a1e7c766f/src/cmd/go/internal/get/path.go#L26:
return fmt.Errorf("malformed import path %q: %v", path, err)
In cmd/go/internal/list/list.go https://github.com/golang/go/blob/6a9d850b82172225b55bd65e830b1e325b17a724/src/cmd/go/internal/list/list.go#L355:
base.Fatalf("%s", err)
我应该使用哪种格式字符串?
我应该使用 %s 还是 %v 来格式化错误?
TL;DR;两者都不。使用%w
在 99.99% 的情况下。在另外 0.001% 的情况下,%v
and %s
可能“应该”表现相同,除非错误值为nil
,但没有任何保证。更友好的输出%v
for nil
错误可能是选择的理由%v
(见下文)。
现在详细介绍:
Use %w
代替%v
or %s
:
从 Go 1.13 开始(或者更早版本,如果您使用golang.org/x/xerrors https://godoc.org/golang.org/x/xerrors),您可以使用%w
动词,仅用于error
值,它包装错误,以便稍后可以使用errors.Unwrap https://golang.org/pkg/errors/#Unwrap,因此可以考虑errors.Is https://golang.org/pkg/errors/#Is and errors.As https://golang.org/pkg/errors/#As.
唯一不合适的时候:
- 您必须支持旧版本的 Go,并且
xerrors
不是一个选择。
- 您想要创建一个独特的错误,并且not包装现有的一个。这可能是合适的,例如,如果您得到
Not found
搜索用户时数据库出错,并且希望将其转换为Unauthorized
回复。在这种情况下,您很少会使用原始错误值any不过,格式化动词。
好吧,那又怎样呢%v
and %s
?
具体如何操作%s
and %v
已实施 可用在文档中 https://golang.org/pkg/fmt/#hdr-Printing。我已经突出显示了与您的问题相关的部分。
-
如果操作数是reflect.Value,则操作数将被它所保存的具体值替换,并继续打印下一条规则。
-
如果操作数实现了 Formatter 接口,它将被调用。格式化程序提供对格式化的精细控制。
-
如果 %v 动词与 # 标志 (%#v) 一起使用并且操作数实现 GoStringer 接口,则将调用该接口。
如果格式(对于 Println 等隐含的是 %v )对于字符串有效 (%s %q %v %x %X),以下两条规则适用:
-
如果操作数实现了错误接口,则将调用Error方法将对象转换为字符串,然后根据动词(如果有)的要求进行格式化。
-
如果操作数实现 String() 字符串方法,则将调用该方法将对象转换为字符串,然后根据动词(如果有)的要求进行格式化。
总而言之,fmt.*f
函数将:
- 寻找一个
Format()
方法,如果存在,他们会调用它。
- 寻找一个
Error()
方法,如果存在,他们会调用它。
- 寻找一个
String()
方法,如果存在,则调用它。
- 使用一些默认格式。
所以在实践中,这意味着%s
and %v
是相同的,除了当Format()
方法存在于错误类型上(或者当错误是nil
)。当错误确实存在时Format()
方法,人们可能希望它能产生与%s
, %v
, and err.Error()
,但由于这取决于错误的实现,因此无法保证,因此这里没有“正确答案”。
最后,如果您的错误类型支持%+v
动词变体,那么如果您想要详细的输出,您当然需要使用它。
nil
values
虽然很少(故意)打电话fmt.*f
on a nil
错误,行为确实有所不同%s
and %v
:
%s: %!s(<nil>)
%v: <nil>
游乐场链接 https://play.golang.org/p/mZYuJof6KQY
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)