英文:
Weird nil / not-nil behavior
问题
我在我的项目中有以下代码:
mod := srt.PrimaryModule()
if mod != nil {
mods[mod.Name()] = mod
}
当执行时,我得到以下错误:
PANIC: runtime error: invalid memory address or nil pointer dereference
错误发生在第三行的mod解引用处。(是的,就是mod解引用,mods映射在上一行创建了...)
那么,什么时候一个nil值不等于nil呢?为什么会这样?
srt.PrimaryModule()返回一个接口类型Module,其中定义了一个返回string类型的Name()方法。
在这个特定的情况下,srt被定义为StdReflectedType类型,它是一个带有返回类型为Module的PrimaryModule()函数的接口类型。srt的实际实现是一个返回未初始化的Module值的结构体。
此外,如果我执行
reflect.ValueOf(mod)
结果是零值的reflect.Value。
根据reflect包的文档:
ValueOf返回一个新的Value,该值初始化为接口i中存储的具体值。ValueOf(nil)返回零值。
这似乎是正确的,但前一行刚刚确定了mod != nil。这是怎么回事?
我似乎无法在一个最小的示例中重现这个问题 - 是否有任何合理的行为可以导致这些行出现这种情况 - 我是否没有理解接口值和nil指针的一些重要内容?
英文:
I have the following code in my project:
mod := srt.PrimaryModule()
if mod != nil {
mods[mod.Name()] = mod
}
When it executes, I get:
PANIC: runtime error: invalid memory address or nil pointer dereference
with the stack right at the third line of that. (Yes it's the mod dereference, the map mods is created just a line above...)
So, when is a nil value not equal to nil? And why?
srt.PrimaryModule()
returns an interface type, Module, with a Name() method defined returning string.
In this particular case, srt is typed StdReflectedType, which is an interface type with a function PrimaryModule() returning type Module. The actual implementation of srt is a struct that returns an uninitialized Module value from its fields.
Further, if I do
reflect.ValueOf(mod)
the result is the zero reflect.Value.
From the reflect package documentation:
ValueOf returns a new Value initialized to the concrete value stored in the interface i. ValueOf(nil) returns the zero Value
Which seems right, except the previous line just determined mod != nil. So what gives?
I cannot seem to reproduce this in a minimal example - is there any sensible behavior that could cause those lines to do this - am I not understandig something important about interface values and nil pointers?
答案1
得分: 2
如果接口中存储了任何具体值,接口将不是nil。然而,存储在接口中的具体值可以是nil指针。
例如,在fmt.Println(mod)的输出中,具体值是否为nil?
if mod != nil {
fmt.Println(mod)
mods[mod.Name()] = mod
}
srt.PrimaryModule()返回一个指向mod的nil指针吗?如果是这样,mod.Name()将会因为nil指针解引用而引发panic。
参考资料:
这个代码的修订版本的输出是什么?
mod := srt.PrimaryModule()
if mod != nil {
fmt.Printf("%T %v\n", mod, mod)
if mod.(Module) != nil {
fmt.Println(mod.Name())
mods[mod.Name()] = mod
}
}
英文:
if any concrete value has been stored in the interface, the interface will not be nil. However, the concrete value stored in the interface can be a nil pointer.
For example, is the fmt.Println(mod) output, the concrete value, nil?
if mod != nil {
fmt.Println(mod)
mods[mod.Name()] = mod
}
Does srt.PrimaryModule() return a nil pointer to mod? If so, mod.Name() will panic with a nil pointer dereference.
References:
The Go Programming Language Specification: Interface types
Go Data Structures: Interfaces
Why is my nil error value not equal to nil?
What is the output from this revised version of your code?
mod := srt.PrimaryModule()
if mod != nil {
fmt.Printf("%T %v\n", mod, mod)
if mod.(Module) != nil {
fmt.Println(mod.Name())
mods[mod.Name()] = mod
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论