Go有标准的Err变量吗?

时间:2015-05-11 21:21:12

标签: go

刚开始使用Golang。我认为声明一个错误变量并在错误结构中使用它来确定出错的地方是惯用的,就像strconv.go中所做的那样。在那里,声明了ErrRangeErrSyntax,并且在适当的时候,对它们的引用在它们返回时存储在NumError结构中。我认为原因是因为可以将NumError中存储的错误引用的地址与ErrRangeErrSyntax变量进行比较,以确定返回了哪种类型的错误。 / p>

是否有"标准"这种声明的错误类型?例如,在Java中,您有java.lang.IllegalArgumentException之类的东西。例如,我可以在我自己的代码中使用ErrArgumentErrUnsupportedOperation,而不是每次都创建同样意义的新错误变量吗?

3 个答案:

答案 0 :(得分:19)

包装作者有一些常见的惯用方法可以使错误返回。

  1. 修正了错误变量,通常名为Err…

    var (
            ErrSomethingBad = errors.New("some string")
            ErrKindFoo      = errors.New("foo happened")
    )
    
  2. 错误类型,通常名为…Error

    type SomeError struct {
         // extra information, whatever might be useful to callers
         // (or for making a nice message in `Error()`)
         ExtraInfo int
    }
    type OtherError string
    
    func (e SomeError) Error() string { /* … */ }
    func (e OtherError) Error() string {
            return fmt.Sprintf("failure doing something with %q", string(e))
    }
    
  3. 根据需要提供临时errors.New值。

    func SomepackageFunction() error {
            return errors.New("not implemented")
    }
    
  4. 使用标准包中定义的错误。通常仅限于io.EOF等小型集合;在大多数情况下,最好通过上面的方法1创建自己的方法。

    func SomeFunc() error {
            return io.EOF
    }
    

    请注意,有时在实现接口(例如Read方法成为io.Reader)时, 最好使用匹配错误(或“必需”接口规范)。

  5. 制作net.Error

    等界面
    type Error interface {
        error
        Timeout() bool   // Is the error a timeout?
        Temporary() bool // Is the error temporary?
    }
    
  6. 通常你会混合使用所有这些方式。

    如果您认为您的软件包的任何用户想要测试特定错误,那么第一个,第二个和第五个是首选。 他们允许这样的事情:

    err := somepkg.Function()
    if err == somepkg.ErrSomethingBad {
            // …
    }
    // or for an error type, something like:
    if e, ok := err.(somepkg.SomeError); ok && e.ExtraInfo > 42 {
            // use the fields/methods of `e` if needed
    }
    

    第五种方式(只是第二种方式的扩展)允许检查行为/类型的错误,如下所示:

    if e, ok := err.(net.Error); ok && e.Timeout() {
            // it's a timeout, sleep and retry
    }
    

    第三种方法的问题是它没有为包的用户提供测试的理智方式。 (测试err.Error()返回的字符串的内容不是一个好主意)。 但是,对于您从未期望任何人想要测试的错误,这很好。

    进一步阅读:

答案 1 :(得分:2)

不,没有。只提供可理解的错误而不是通用错误。 IllegalArgument运输什么信息?不多,不够。

答案 2 :(得分:2)

如您所见,特定包使用了特定错误。例如,在database/sql包中,他们定义:

var ErrNoRows = errors.New("sql: no rows in result set")

因此,如果您执行QueryRow(将错误推迟到Scan),然后Scan,则可以执行

if  err := row.Scan(&data); err != nil && err != sql.ErrNoRows {
    //something actually went wrong
} else if err != nil {
    //no results
} else {
    //we found it
}

os/execvar ErrNotFound = errors.New("executable file not found in $PATH")

encoding/json有一个type UnmarshalTypeError,它只是一种实现error接口的类型。

所以不,虽然没有"标准错误和#34;但您可以(并且很可能应该)具有您重复使用的特定错误变量。

您可以拥有自己使用的errorMsgs包,可以重用常见错误:

err := doSomething(); if err != nil {
    switch err {
        case errorMsgs.IllegalArgument:
           //do something
        case errorMsgs.CouldNotConnect:
           //do something else
     }
}