String 我应该使用%s或%v格式化错误吗

String 我应该使用%s或%v格式化错误吗,string,go,error-handling,formatting,String,Go,Error Handling,Formatting,%s和%v都可以用来格式化Go中的错误,而且似乎没有功能上的区别,至少表面上是这样 我们在Go自己的工具中看到了这两者 在: 返回fmt.Errorf(“格式错误的导入路径%q:%v”,路径,错误) 在: base.Fatalf(“%s”,err) 我应该更喜欢其中一个吗?使用%v作为错误值 如果出错!=零{ 返回fmt.Errorf(“包%v:%v”,名称,错误) } 但是,在Go 1.13中,fmt.Errorf函数支持一个新的%w动词。当存在此谓词时,fmt.Errorf返回的错误将有一

%s
%v
都可以用来格式化Go中的错误,而且似乎没有功能上的区别,至少表面上是这样

我们在Go自己的工具中看到了这两者

在:
返回fmt.Errorf(“格式错误的导入路径%q:%v”,路径,错误)

在:
base.Fatalf(“%s”,err)


我应该更喜欢其中一个吗?

使用
%v
作为错误值

如果出错!=零{
返回fmt.Errorf(“包%v:%v”,名称,错误)
}
但是,在
Go 1.13
中,
fmt.Errorf
函数支持一个新的
%w
动词。当存在此谓词时,
fmt.Errorf
返回的错误将有一个
Unwrap
方法返回
%w
的参数,该参数必须为错误。在所有其他方面,
%w
%v
相同

如果出错!=零{
//返回一个展开为err的错误。
返回fmt.Errorf(“包%v:%w”,名称,错误)
}
需要区分
%w
%v
的位置:

%s: %!s(<nil>)
%v: <nil>
阅读代码块中的注释

f,err:=os.Open(文件名)
如果出错!=零{
//os.Open返回的*os.PathError是一个内部详细信息。
//为了避免将其暴露给调用者,请将其重新打包为新文件
//相同文本的错误。
//
//
//我们使用%v格式动词,因为
//%w将允许调用方打开原始*os.PathError。
返回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

我应该使用%s或%v格式化错误吗

TL;博士%w。在其他0.001%的情况下,
%v
%s
可能“应该”表现相同,除非错误值为
nil
,但没有保证。对于
nil
错误,
%v
的友好输出可能是首选
%v
的原因(见下文)

详情如下:

使用
%w
而不是
%v
%s
: 从Go 1.13(或更早版本,如果您使用的话)开始,您可以使用
%w
动词,仅用于
错误
值,该动词包装错误,以便以后可以使用展开,并且可以考虑使用和

唯一不合适的情况是:

  • 您必须支持较旧版本的Go,并且不能选择
    xerrors
  • 您希望创建唯一错误,而不是包装现有错误。例如,如果在搜索用户时从数据库中获得
    未找到
    错误,并希望将其转换为
    未经授权的
    响应,则这可能是合适的。在这种情况下,很少会将原始错误值与任何格式动词一起使用
  • 好的,那么
    %v
    %s
    呢? 有关如何实现
    %s
    %v
    的详细信息可用。我已经强调了与你的问题相关的部分

  • 如果操作数是一个reflect.Value,则该操作数将替换为它所持有的具体值,并继续打印下一条规则

  • 如果操作数实现格式化程序接口,将调用该接口。格式化程序提供格式的精细控制

  • 如果%v谓词与#标志(%#v)一起使用,并且操作数实现了GoStringer接口,则将调用该接口

    如果格式(对于Println等隐式为%v)对字符串(%s%q%v%x%x)有效,则以下两条规则适用

  • 如果操作数实现了错误接口,将调用error方法将对象转换为字符串,然后按照谓词(如果有)的要求格式化字符串

  • 如果操作数实现方法String()String,将调用该方法将对象转换为字符串,然后按照谓词(如果有)的要求格式化字符串

  • 总之,
    fmt.*f
    功能将:

  • 查找
    Format()
    方法,如果它存在,他们将调用它
  • 查找
    Error()
    方法,如果它存在,他们将调用它
  • 查找
    String()
    方法,如果它存在,则调用它
  • 使用一些默认格式
  • 因此,在实践中,这意味着
    %s
    %v
    是相同的,除非错误类型上存在
    格式()
    方法(或者错误为
    nil
    )。当一个错误确实有一个
    Format()
    方法时,人们可能希望它将产生与
    %s
    %v
    err.error()
    相同的输出,但由于这取决于错误的实现,因此没有保证,因此这里没有“正确答案”

    最后,如果您的错误类型支持
    %+v
    动词变体,那么您当然需要使用它,如果您需要详细的输出

    nil
    值 虽然很少(故意)在出现
    nil
    错误时调用
    fmt.*f
    ,但
    %s
    %v
    之间的行为确实不同:

    %s: %!s(<nil>)
    %v: <nil>
    
    %s:%!s()
    %五: