本片文章用来记录我在 Golang 开发学习过程中遇到的有关 error 的一些坑。或许你也遇到,或许你能在这里找到答案。当然通过 error 的例子,你也应该联想到其它场景。
err != nil
第一个问题是:为什么值为 nil 的 error 却不等于 nil?
思考如下代码:
package main
import (
"errors"
"fmt"
)
type Err struct {
err string
}
func (e *Err) Error() string {
return e.err
}
func returnErr() *Err {
return nil
}
func main() {
var err error
err = returnErr()
fmt.Println(err, err != nil)
}
首先 returnErr()
返回了一个值为 nil 的 *Err,然后赋值给了 err,那么 fmt 会打印什么结果?是不是:
<nil> false
错,它会打印 <nil> true
。当时自己也是没有头绪,学艺不精,问过大神才知道,这是接口 interface 造成的。具体可以查看 官网 FAQ。
简单说,interface 被两个元素 value 和 type 所表示。只有在 value 和 type 同时为 nil 的时候,判断 interface == nil
才会为 true。而 err = returnErr()
这个过程中,虽然 value 为 nil,但 type 却为 *Err。
如何解决这个问题呢?在我看来只能从根源上着手,两种方式:
- 不要将该结果赋给一个接口变量。如,将
err = returnErr()
改成err1 := returnErr()
,这样就可以避免造成的干扰。 不要让函数返回自定义类型,如,*Err。应该将错误包装过滤为 error,如:
func Err() (err error) { if e := returnErr(); e != nil { return e } return }
err == nil
为什么还有 err == nil
的问题呢?这个问题是我看查看标准库源码的时候发现的,其中有这么一段:
func (e *AddrError) Error() string {
if e == nil { // 请注意,为什么这里会判断是否为 nil
return "<nil>"
}
s := e.Err
if e.Addr != "" {
s = "address " + e.Addr + ": " + s
}
return s
}
为什么会再次去判断 e == nil
,当时很是费解。众所周知,方法(姑且这样说)和变量是存储在不同区域的,当我们用一个空指针类型的变量(如,var e *AddrError)调用方法时,该方法是会执行的,只有在执行该空指针变量的解指针操作时,才会 panic。
下面是一个例子:
// Package main provides ...
package main
import "fmt"
func main() {
var e *Err
e.Print()
e.Printf()
e.Println()
}
type Err struct {
err string
}
func (e *Err) Print() {
fmt.Println("e.Print run")
}
func (e *Err) Printf() {
fmt.Println(e.err)
}
func (e Err) Println() {
fmt.Println("e.Println run")
}
1、e.Print()
是完全可以执行的,没有解指针操作。
2、e.Printf()
在调用 e.err 的时候,发生了解指针操作,故会 panic。
3、e.Println()
由于接受者是 Err 而不是 *Err,Golang 内部在调用该函数时,会自动解指针,故会 panic。
本文链接:https://deepzz.com/post/why-nil-error-not-equal-nil.html,参与评论 »
--EOF--
发表于 2017-05-14 08:55:00,并被添加「golang、error」标签。
本站使用「署名 4.0 国际」创作共享协议,转载请注明作者及原网址。更多说明 »
提醒:本文最后更新于 2748 天前,文中所描述的信息可能已发生改变,请谨慎使用。
专题「Go 踩坑系列」的其它文章 »
- Go 测试,go test 工具的具体指令 flag (May 20, 2018)
- Go 单元测试,基准测试,http 测试 (May 09, 2018)
- Go 关键字 defer 的一些坑 (Aug 27, 2017)
- 浅谈 Golang sync 包的相关使用方法 (Aug 19, 2017)
- Glide命令,如何使用glide,glide.lock (Feb 09, 2017)
- Golang包管理工具Glide,你值得拥有 (Feb 07, 2017)
Comments