Go中error类型的nil值和nil
先看C语言中的类似问题:空字符串。
以上3个字符串并不相等,但是从某种角度看,它们都是对应空的字符串。
Go的error是一个interface类型,error的nil问题和C语言的字符串类似。 参考官方的error文档说明:
在底层,interface作为两个成员实现:一个类型和一个值。该值被称为接口的动态值, 它是一个任意的具体值,而该接口的类型则为该值的类型。对于 int 值3, 一个接口值示意性地包含(int,3)。 只有在内部值和类型都未设置时(nil,nil),一个接口的值才为 nil。特别是,一个 nil 接口将总是拥有一个 nil 类型。若我们在一个接口值中存储一个int 类型的指针,则内部类型将为int,无论该指针的值是什么:(*int,nil)。 因此,这样的接口值会是非 nil 的,即使在该指针的内部为 nil。 下面是一个错误的错误返回方式: func returnsError() error { |
var p *MyError = nil
if bad() { |
5 | } |
p
// Will always return a non-nil error.
7 | } |
这里 p 返回的是一个有效值(非nil),值为 nil。
类似上面的 empty_str0。
因此,下面判断错误的代码会有问题:
panic(nil) |
针对 returnsError 的问题,可以这样处理(不建议的方式):
err := returnsError(); err.(*MyError) != nil { |
在判断前先将err转型为*MyError,然后再判断err的值。 类似的C语言空字符串可以这样判断: bool IsEmptyStr( * str) { |
0
] !=
' '
);
但是Go语言中标准的错误返回方式不是returnsError这样。 下面是改进的returnsError: nil |
因此,在处理错误返回值的时候,一定要将正常的错误值转换为 nil。
比如,syscall中就有一个bug是由于没有处理好error导致的: 01 |
// syscall: (*Proc).Call always returns non-nil err |
03 | packagemain |
05 | import"syscall" |
"kernel32.dll"
)
09 | proc := h.MustFindProc("GetVersion" ) |
11 | major :=byte (r) |
8
13
16
14
"windows version "
,major,
"."
" (Build "
")n"
15
17 | println(err.Error(),monospace!important; border:0px!important; color:blue!important; outline:0px!important; float:none!important; vertical-align:baseline!important; position:static!important; left:auto!important; top:auto!important; right:auto!important; bottom:auto!important; height:auto!important; width:auto!important; line-height:1.1em!important; font-size:10pt!important; min-height:inherit!important">"errno ="18 |
19 | 目前issues4686这个bug已经在修复中。
作为用户,临时可以用前面的方法回避这个bug:
// https://code.google.com/p/go/issues/detail?id=4686 |
func call(h *syscall.LazyDLL,name string, |
r1,r2,err = h.NewProc(name).Call(a...) |
{
return |
这样可以回避很多类似C语言中因为隐式类型转换引入的bug。
但是,Go中interface是一个例外:type到interface和interface之间可能是隐式转换的。 或许,这是Go做得不太好的地方吧。
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!