在Go中使用自定义Error
类型(使用额外字段捕获一些详细信息)时,尝试将nil
作为此类型的值返回时,会出现cannot convert nil to type DetailedError
之类的编译错误或者像cannot use nil as type DetailedError in return argument
一样,从代码看起来像这样:
type DetailedError struct {
x, y int
}
func (e DetailedError) Error() string {
return fmt.Sprintf("Error occured at (%s,%s)", e.x, e.y)
}
func foo(answer, x, y int) (int, DetailedError) {
if answer == 42 {
return 100, nil //!! cannot use nil as type DetailedError in return argument
}
return 0, DetailedError{x: x, y: y}
}
(完整摘录:https://play.golang.org/p/4i6bmAIbRg)
解决这个问题的惯用方法是什么?(或任何有效的方法......)
我实际上需要有关错误的额外字段,因为我有更简单的复杂逻辑构造的详细错误消息等,如果我只是回到“字符串错误”,我基本上必须解析< / em>那些字符串碎片并且逻辑基于它们发生等等,这看起来真的很难看(我的意思是,为什么序列化到字符串信息,你知道你以后需要反序列化...)
答案 0 :(得分:12)
请勿使用DetailedError
作为返回类型,请始终使用error
:
func foo(answer, x, y int) (int, error) {
if answer == 42 {
return 100, nil //!! cannot use nil as type DetailedError in return argument
}
return 0, DetailedError{x: x, y: y}
}
您的DetailedError
类型满足error
接口的事实足以使其工作。然后,在调用者中,如果您关心额外的字段,请使用类型断言:
value, err := foo(...)
if err != nil {
if detailedErr, ok := err.(DetailedError); ok {
// Do something with the detailed error values
} else {
// It's some other error type, behave accordingly
}
}
未退回DetailedError
的原因:
现在看起来似乎不重要,但将来您的代码可能会扩展到包含其他错误检查:
func foo(answer, x, y int) (int, error) {
cache, err := fetchFromCache(answer, x, y)
if err != nil {
return 0, fmt.Errorf("Failed to read cache: %s", err)
}
// ...
}
其他错误类型不属于DetailedError
类型,因此您必须返回error
。
此外,您的方法可能会由不了解或不关心DetailedError
类型的其他来电者使用:
func fooWrapper(answer, x, y int) (int, error) {
// Do something before calling foo
result, err := foo(answer, x, y)
if err != nil {
return 0, err
}
// Do something after calling foo
return result, nil
}
期望函数的每个调用者都能理解自定义错误类型是不合理的 - 这正是Go中存在接口,特别是error
接口的原因。
利用这一点,不要绕过它。
即使你的代码永远不会改变,每个函数或用例都有一个新的自定义错误类型是不可持续的,并且使你的代码不可读并且无法推理。
答案 1 :(得分:1)
DetailedError struct
零值不是nil
,而是DetailedError{}
。您可以返回error
界面而不是DetailedError
func foo(answer, x, y int) (int, error) {
或使用指针
func foo(answer, x, y int) (int, *DetailedError) {
...
//and
func (e *DetailedError) Error() string {
答案 2 :(得分:-1)
解决问题的惯用方法是返回错误界面。
如果您实际上需要一个不属于错误接口的功能,则应创建一个扩展错误接口的新接口。
type DetailedErrorInterface interface {
error
GetX() int //need to implement
GetY() int //need to implement
}
然后,您必须更改函数以返回此接口:
func foo(answer, x, y int) (int, DetailedErrorInterface) {
if answer == 42 {
return 100, nil
}
return 0, DetailedError{x: x, y: y}
}