%s
和%v
都可以用来格式化Go中的错误,并且至少在表面上似乎没有功能上的区别。
我们在Go自己的工具中都看到了。
在cmd/go/internal/get/path.go中:return fmt.Errorf("malformed import path %q: %v", path, err)
在cmd/go/internal/list/list.go中:base.Fatalf("%s", err)
我应该比另一个更喜欢吗?
我应该使用%s或%v格式化错误吗?
TL; DR;都没有。在99.99%的情况下使用%w
。在其他0.001%的情况下,%v
和%s
可能“应该”表现相同,但是没有保证。
现在为详细信息:
%w
代替%v
或%s
:从Go 1.13开始(或更早,如果使用golang.org/x/xerrors,则可以将%w
动词用于仅error
值),该动词将错误包装起来,以便以后可以用errors.Unwrap
进行包装。以便可以与errors.Is
和errors.As
一起考虑。
唯一不适合的时间:
xerrors
不是一个选项。Not found
错误,并且想要将此错误转换为Unauthorized
响应,则这可能是适当的。在这种情况下,很少会在any格式化动词上使用原始错误值。%v
和%s
呢?有关如何实现%s
和%v
的详细信息,请参见in the docs。我已突出显示与您的问题有关的部分。
如果操作数是一个reflect.Value,操作数将替换为其所持有的具体值,并使用下一条规则继续打印。
如果操作数实现Formatter接口,它将被调用。 Formatter提供了良好的格式化控制。
如果%v动词与#标志(%#v)一起使用,并且操作数实现GoStringer接口,则将被调用。
如果格式(对于Println等而言是隐含的%v。)对于字符串有效(%s%q%v%x%X),以下两个规则适用:
如果操作数实现错误接口,则将调用Error方法将对象转换为字符串,然后将根据动词的要求对其进行格式化(如果有)。
如果操作数实现方法String()字符串,则将调用该方法将对象转换为字符串,然后将根据动词的要求对其进行格式化(如果有)。
总而言之,fmt.*f
功能将:
Format()
方法,如果存在,他们会调用它。Error()
方法,如果存在,他们会调用它。String()
方法,如果存在,则调用它。因此,实际上,这意味着%s
和%v
是相同的,除了在错误类型上存在Format()
方法时除外。当错误确实具有Format()
方法时,可能希望它会与%s
,%v
和err.Error()
产生相同的输出,但是由于这取决于错误的实现,因此没有错误保证,因此这里没有“正确答案”。
使用%v
作为错误值。>>
if err != nil { return fmt.Errorf("pack %v: %v", name, err) }
但是,在
Go 1.13
中,fmt.Errorf
函数支持新的%w
动词。当存在该动词时,由fmt.Errorf
返回的错误将具有Unwrap
方法,该方法返回%w
的参数,该参数必须是错误。在所有其他方式下,%w
与%v
相同。
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)
}
此外,内置的错误接口允许Go程序员添加所需的任何信息。它所需要的只是一种实现Error
方法的类型
示例:
type QueryError struct { Query string Err error } func (e *QueryError) Error() string { return e.Query + ": " + e.Err.Error() }
因此,大多数示例都具有类似的实现方式,其中
err
具有Error
方法,该方法返回您可以使用string
的%s