go - 如何检测自定义错误
问题描述
动机
我有一个名为CustomError的自定义错误类型,我想编写一个将任何类型的错误解析到我的错误结构中的方法。所以我写了parse方法给你看。我将在任何返回错误接口的函数上使用parse方法。因此,所有错误都将根据我的类型进行结构化。
问题
当我使用带有 nil 值的parse方法返回错误接口时,返回的错误不是 nil。代码如下。第一次测试成功,但第二次没有。
const (
UnHandledError = "UnHandledError"
CircuitBreakerError = "CircuitBreakerError"
)
type CustomErrorType struct {
Key string
Message string
Status int
}
func (c *CustomErrorType) Error() string {
return "Custom error message"
}
func parse(err error) *CustomErrorType {
if err == nil {
return nil
}
if e, ok := err.(*CustomErrorType); ok {
return e
}
if e, ok := err.(hystrix.CircuitError); ok {
return &CustomErrorType{CircuitBreakerError, e.Message, http.StatusTooManyRequests}
}
return &CustomErrorType{UnHandledError, err.Error(), http.StatusInternalServerError}
}
func TestParse_it_should_return_nil_when_error_is_nil(t *testing.T) {
result := parse(nil)
if result != nil {
t.Error("result is not nil")
}
}
func TestParse_it_should_return_nil_when_error_is_nil_2(t *testing.T) {
aFunc := func() error {
return parse(nil)
}
result := aFunc()
if result != nil {
t.Error("result is not nil")
}
}
你能解释一下我错过了什么或有什么问题吗?
解决方案
这是 go 接口的一个常见“问题”的一个实例,它是由底层接口的实际实现引起的:包含nil
指针的接口不是 - nil
。
它在 go's faq 中描述了一个类似于你的error
接口情况的例子:为什么我的 nil 错误值不等于 nil?
在幕后,接口被实现为两个元素,一个类型
T
和一个值V
。V
是一个具体的值,例如 an或int
,从不是接口本身,并且具有 type 。struct
pointer
T
...
接口值
nil
仅在V
和T
都未设置时,(T=nil, V is not set)
,特别是,nil
接口将始终保存一个nil
类型。如果我们将nil
类型指针存储*int
在接口值中,则内部类型将*int
与指针的值无关:(T=*int, V=nil)
。V
因此,即使内部的指针值为 ,这样的接口值也将非零nil
。这种情况可能会令人困惑,并且当
nil
值存储在接口值中时会出现这种情况,例如错误返回:func returnsError() error { var p *MyError = nil if bad() { p = ErrBad } return p // Will always return a non-nil error. }
此示例类似于您执行此操作时代码中发生的情况:
aFunc := func() error {
return parse(nil)
}
parse()
返回*CustomErrorType
,但只是error
使值返回的函数返回一个包含类型和nil
值的接口:(T=*CustomErrorType, V=nil)
反过来,它的计算结果为 not- nil
。
然后常见问题解答继续提供解释并显示“正确”示例:
如果一切顺利,函数返回一个
nil
p,所以返回值是一个error
接口值holding(T=*MyError, V=nil)
。这意味着,如果调用者将返回的error
与进行比较nil
,即使没有发生任何不好的事情,它也总是看起来好像有错误。要向调用者返回正确的nil
错误,函数必须返回显式nil
:func returnsError() error { if bad() { return ErrBad } return nil }
在您的示例中也可以观察到该行为,添加一个
fmt.Printf("%#v\n", result)
打印result
的值:
(*e.CustomErrorType)(nil)
如果我们将parse()
返回类型更改为 just error
,它将打印:
<nil>
推荐阅读
- c++ - 如何为 std::variant 赋值?
- python - 如何对多索引系列进行切片
- python-3.x - 在 Python 中使用 BeautifulSoup 和 Requests 抓取表数据
- tensorflow - 如何正确利用 GPU 能力?
- sql - SQL 使用联接并将 2 行从一个联接合并到具有不同列中的值的一行
- python - 使用python将ascii转换为sac
- java - 制作jar时eclipse找不到main方法
- php - 如何在应用安装期间自动在购物车液体中注入 {% include snippetname.liquid %}?
- django - 如何在 Django 后端使用 Angular 数据表
- java - 错误 com.sun.jersey.api.client.ClientHandlerException: java.net.UnknownHostException: abcd-local.us.company