什么是在Go语言中分组错误的最佳方式?

huangapple go评论76阅读模式
英文:

What is the best way to group errors in go?

问题

我在查看net/http和crypto/x509。

我想知道哪种方法更好,以及为什么。

net/http/http.go使用了字符串:

// HTTP请求解析错误。
type ProtocolError struct {
  ErrorString string
}

func (err *ProtocolError) Error() string { return err.ErrorString }

var (
  ErrHeaderTooLong        = &ProtocolError{"header too long"}
  ErrShortBody            = &ProtocolError{"entity body too short"}
  ErrNotSupported         = &ProtocolError{"feature not supported"}
  ErrUnexpectedTrailer    = &ProtocolError{"trailer header without chunked transfer encoding"}
  ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"}
  ErrNotMultipart         = &ProtocolError{"request Content-Type isn't multipart/form-data"}
  ErrMissingBoundary      = &ProtocolError{"no multipart boundary param in Content-Type"}
)

crypto/x509/verify.go使用了整数:

type InvalidReason int

const (
  TooManyIntermediates
  IncompatibleUsage
)

type CertificateInvalidError struct {
  Cert   *Certificate
  Reason InvalidReason
}

func (e CertificateInvalidError) Error() string {
  switch e.Reason {
  case TooManyIntermediates:
    return "x509: too many intermediates for path length constraint"
  case IncompatibleUsage:
    return "x509: certificate specifies an incompatible key usage"
  }
  return "x509: unknown error"
}
英文:

I was looking at net/http and crypto/x509

I wondering which approach is better and why.

net/http/http.go uses strings:

// HTTP request parsing errors.
type ProtocolError struct {
  ErrorString string
}

func (err *ProtocolError) Error() string { return err.ErrorString }

var (
  ErrHeaderTooLong        = &ProtocolError{"header too long"}
  ErrShortBody            = &ProtocolError{"entity body too short"}
  ErrNotSupported         = &ProtocolError{"feature not supported"}
  ErrUnexpectedTrailer    = &ProtocolError{"trailer header without chunked transfer encoding"}
  ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"}
  ErrNotMultipart         = &ProtocolError{"request Content-Type isn't multipart/form-data"}
  ErrMissingBoundary      = &ProtocolError{"no multipart boundary param in Content-Type"}
)

crypto/x509/verify.go uses ints:

type InvalidReason int

const (
  TooManyIntermediates
  IncompatibleUsage
)

type CertificateInvalidError struct {
  Cert   *Certificate
  Reason InvalidReason
}

func (e CertificateInvalidError) Error() string {
  switch e.Reason {
  case TooManyIntermediates:
    return "x509: too many intermediates for path length constraint"
  case IncompatibleUsage:
    return "x509: certificate specifies an incompatible key usage"
  }
  return "x509: unknown error"
}

答案1

得分: 1

两种用法都可以,但这取决于你的需求。

如果你发现附加额外数据到错误中对于错误消息来说很有用,那么crypto/x509中的方法更可取。

但我认为在大多数情况下,errors包中的简单错误字符串就足够了。

编辑

一个错误可以有不同的“属性”:

描述性
Error()方法应该返回一个简短的描述性错误消息。

可识别性
通过让一个包导出可能返回的不同错误,你可以对它们进行识别。这可以像io包一样通过导出相同类型的初始化错误变量来完成:

if err == io.EOF { ... } // 这很简单

或者像encoding/json包一样通过导出不同的错误类型来完成:

if mErr, ok := err.(*json.MarshalerError); ok { ... } // 这相当简单

或者像crypto/x509包中所做的那样,通过导出不同的原因(错误代码)来完成:

if e, ok := err.(x509.CertificateInvalidError); ok && e.Reason == x509.Expired  { ... } // 嗯,它可以工作

唯一错误代码
如果错误应该有特定的代码,这些代码可以嵌入到错误变量中。crypto/x509包可能会用于此,尽管这可能不是情况。

但是,当涉及到如何解决它时,我认为没有最佳方法,也没有明确的惯用方法。上面的示例向你展示了如何做以及在标准库中是如何做的。你可以自行选择。

.. 但也许不要使用switch语句。

英文:

Both usage are good, but it depends on your needs.

If you find it useful to attach additional data to the error that doesn't show in the error message, then the approach in crypto/x509 is preferable.

But I think in most cases, the simple error string as found in the errors package is sufficient.

Edit

An error can have different "attributes":

Describing
The Error() method should return a short describing error message

Identifiable
By letting a package export the different errors it might return, you can identify them. This is either done like in the io package by exporting initialized error variables of same type:

if err == io.EOF { ... } // That's easy

Or like in the encoding/json package by exporting the different error types:

if mErr, ok := err.(*json.MarshalerError); ok { ... } // That's fairly easy

Or by doing like they do in the crypto/x509 package, by exporting the different Reasons (error codes):

if e, ok := err.(x509.CertificateInvalidError); ok && e.Reason == x509.Expired  { ... } // Well, it works

Unique error code
If errors should have specific codes due to a protocol spec, these could be embedded in the error variable. The crypto/x509 package might be used for that, even though it is probably not the case.

But when it comes to how to solve it, I think there is no best approach, nor any clearly idiomatic one. The examples above shows you ways to do it and ways it is done in the standard libraries. Take your pick.

.. but maybe not using switch statements.

huangapple
  • 本文由 发表于 2013年7月11日 22:02:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/17595502.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定