问题:在一个nil变量上调用函数,会发生什么?
一般会认为panic。为了不发生panic,每次调用方法前,都要判断变量是否为nil。这么做虽然没错,但终究使代码看起来不那么优雅。
那么一定会panic吗?
让我们来做个实验
type PlanConfig struct {
No int64
}
func (p *PlanConfig) IsEmpty() bool {
if p == nil {
fmt.Println("hello")
return false
}
return reflect.ValueOf(*p).IsZero()
}
var p *PlanConfig
fmt.Println(p)
fmt.Println(p.IsEmpty())
该代码会输出
hello
false
可以看到,新声明的指针类型变量p,是nil,但是并不妨碍他调用IsEmpty()方法。
【go里边一个让新手误解,让老炮犯错的小知识点】如果强制赋nil呢,还会执行吗?
type PlanConfig struct {
No int64
}
func (p *PlanConfig) IsEmpty() bool {
if p == nil {
fmt.Println("hello")
return false
}
return reflect.ValueOf(*p).IsZero()
}
var p *PlanConfig
fmt.Println(p)
p = nil
fmt.Println(p.IsEmpty())
依然输出
hello
false
是不是很顽强。
再模拟一下我们实际代码中的用法,比如从一个函数获取某个变量,但是返回值nil,然后用这个变量调用方法
type PlanConfig struct {
No int64
}
func (p *PlanConfig) IsEmpty() bool {
if p == nil {
fmt.Println("hello")
return false
}
return reflect.ValueOf(*p).IsZero()
}func getPlan() *PlanConfig {
return nil
}
p := getPlan()
fmt.Println(p.IsEmpty())
输出
hello
false
这样我们只需要在方法的入口处判断一次即可,而不用每次调用方法前,都判断变量是否为nil了。
我们再看看,程序会崩的情况。
type PlanConfig struct {
No int64
}
func (p *PlanConfig) IsEmpty() bool {
if p == nil {
fmt.Println("hello")
return false
}
return reflect.ValueOf(*p).IsZero()
}p := nil
fmt.Println(p.IsEmpty())
ide直接会飘红。执行代码也会抛出错误
use of untyped nil
再看这种
type PlanConfig struct {
No int64
}
func (p *PlanConfig) IsEmpty() bool {return reflect.ValueOf(*p).IsZero()
}func getPlan() *PlanConfig {
return nil
}
p := getPlan()
fmt.Println(p.IsEmpty())
这一次,我们在方法 IsEmpty()入口处去掉 nil判断,结果确实会发生panic。
结论:
用指针作为方法接收者的时候,只要我们在函数入口处做是否为nil的判断,那么就可以尽情去享受go带来的便利了。
推荐阅读
- 为什么 signal.Notify 使用缓冲通道()
- Go中的网络轮询器(1)--Epoll在Go中的抽象
- net包的使用
- atomic
- 条件变量 Cond
- 类型别名与类型定义的区别
- Go|猿创征文|我的Go成长之路道阻且长
- go-常用类库
- GoLand 2022 注册码