英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论