如何创建一个自定义错误,它是另一个自定义错误的子类型,比如继承?
How to create a custom error that's a subtype of another custom error, like inherited?
对于给定的自定义错误类型:
type CustomError struct {
// Err optionally wraps the original error.
Err error `json:"-"`
// Human readable message.
Message string `json:"message" validate:"required,gte=3"`
// StatusCode is a valid HTTP status code, e.g.: 404.
StatusCode int `json:"-"`
}
实现了Error() string
和Unwrap() error
接口,还有一个工厂:
func NewCustomError(m string, s int, e error) *CustomError {}
如何基于 CustomType
创建另一个“类型”- 我们将其称为 FailedTo
以解决诸如 “无法创建 X” 之类的错误默认情况下:
- A 前缀为
Message
和 Failed to
500
的状态码
除此之外,还有一个,例如 FailedToCreateSomething
,在某种程度上......
func createSomething() error {
return FailedToCreateSomething(errors.New("File is busy"))
}
errCreateSomething := createSomething()
...errCreateSomething
是 FailedToCreateSomething
的类型,也是 FailedTo
和 CustomError
?
的类型
让我们从示例中提炼出它的本质。
package customerror
import (
"errors"
)
type CustomError struct {
Aux string
Err error
}
func (cE *CustomError) Error() string { /*...*/ }
func (err *CustomError) Unwrap() error { return err.Err }
func NewFailedToError(aux string, err error) error {
return &CustomError{ Aux: aux, Err: err }
}
var FailedToWriteToFile = NewFailedToError("write to file", nil)
我们现在可以进入要点:
// Some function just for demonstration.
func WriteToFile() error {
// Something caused some error..
errSome := errors.New("Failed to open file")
// How can I set the `err` value of `FailedToWriteToFile` to `errSome`
// without setting that for all `FailedToWriteToFile` instances (pointer)?
// while still making it of `FailedToWriteToFile` type (errors.Is(errSome, FailedToWriteToFil))?
return FailedToWriteToFile
}
让我们将这个问题重新定义为如何使用包含 errors.Is(errSome, FailedToWriteToFil)
的新消息制作 errSome
。
我们可以查看 errors.Is
:
的文档
Is reports whether any error in err's chain matches target.
The chain consists of err itself followed by the sequence of errors obtained by repeatedly calling Unwrap.
An error is considered to match a target if it is equal to that target or if it implements a method Is(error) bool such that Is(target) returns true.
An error type might provide an Is method so it can be treated as equivalent to an existing error. For example, if MyError defines
func (m MyError) Is(target error) bool { return target == fs.ErrExist }
then Is(MyError{}, fs.ErrExist) returns true. See syscall.Errno.Is for an example in the standard library.
这给了我们两条路。路径之一是将 FailedToWriteToFile
放在 Unwrap 链上。如果我们使用 Err 字段指向 FailedToWriteToFile
,则 CustomError 有足够的字段,例如
&CustomError{Aux: "Failed to open file", Err: FailedToWriteToFile}
Unwrap() 在此 == 到 FailedToWriteToFile
。如果您试图捕获来自另一个来源的错误值,FWIW Aux 可能是错误类型的字段。只要 Unwrap() 链最终导致 FailedToWriteToFile
。
另一个途径是在CustomError
上定义一个Is
谓词。有很多可能的谓词可供选择。一个简单的方法是所有 *CustomError 都被认为是等价的。那将是:
func (e *CustomError) Is(target error) bool {
_, ok := target.(*CustomError)
return ok
}
对于给定的自定义错误类型:
type CustomError struct {
// Err optionally wraps the original error.
Err error `json:"-"`
// Human readable message.
Message string `json:"message" validate:"required,gte=3"`
// StatusCode is a valid HTTP status code, e.g.: 404.
StatusCode int `json:"-"`
}
实现了Error() string
和Unwrap() error
接口,还有一个工厂:
func NewCustomError(m string, s int, e error) *CustomError {}
如何基于 CustomType
创建另一个“类型”- 我们将其称为 FailedTo
以解决诸如 “无法创建 X” 之类的错误默认情况下:
- A 前缀为
Message
和Failed to
500
的状态码
除此之外,还有一个,例如 FailedToCreateSomething
,在某种程度上......
func createSomething() error {
return FailedToCreateSomething(errors.New("File is busy"))
}
errCreateSomething := createSomething()
...errCreateSomething
是 FailedToCreateSomething
的类型,也是 FailedTo
和 CustomError
?
让我们从示例中提炼出它的本质。
package customerror
import (
"errors"
)
type CustomError struct {
Aux string
Err error
}
func (cE *CustomError) Error() string { /*...*/ }
func (err *CustomError) Unwrap() error { return err.Err }
func NewFailedToError(aux string, err error) error {
return &CustomError{ Aux: aux, Err: err }
}
var FailedToWriteToFile = NewFailedToError("write to file", nil)
我们现在可以进入要点:
// Some function just for demonstration.
func WriteToFile() error {
// Something caused some error..
errSome := errors.New("Failed to open file")
// How can I set the `err` value of `FailedToWriteToFile` to `errSome`
// without setting that for all `FailedToWriteToFile` instances (pointer)?
// while still making it of `FailedToWriteToFile` type (errors.Is(errSome, FailedToWriteToFil))?
return FailedToWriteToFile
}
让我们将这个问题重新定义为如何使用包含 errors.Is(errSome, FailedToWriteToFil)
的新消息制作 errSome
。
我们可以查看 errors.Is
:
Is reports whether any error in err's chain matches target.
The chain consists of err itself followed by the sequence of errors obtained by repeatedly calling Unwrap.
An error is considered to match a target if it is equal to that target or if it implements a method Is(error) bool such that Is(target) returns true.
An error type might provide an Is method so it can be treated as equivalent to an existing error. For example, if MyError defines
func (m MyError) Is(target error) bool { return target == fs.ErrExist }
then Is(MyError{}, fs.ErrExist) returns true. See syscall.Errno.Is for an example in the standard library.
这给了我们两条路。路径之一是将 FailedToWriteToFile
放在 Unwrap 链上。如果我们使用 Err 字段指向 FailedToWriteToFile
,则 CustomError 有足够的字段,例如
&CustomError{Aux: "Failed to open file", Err: FailedToWriteToFile}
Unwrap() 在此 == 到 FailedToWriteToFile
。如果您试图捕获来自另一个来源的错误值,FWIW Aux 可能是错误类型的字段。只要 Unwrap() 链最终导致 FailedToWriteToFile
。
另一个途径是在CustomError
上定义一个Is
谓词。有很多可能的谓词可供选择。一个简单的方法是所有 *CustomError 都被认为是等价的。那将是:
func (e *CustomError) Is(target error) bool {
_, ok := target.(*CustomError)
return ok
}