奇怪的 nil / not-nil 行为

huangapple go评论85阅读模式
英文:

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类型,它是一个带有返回类型为ModulePrimaryModule()函数的接口类型。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()返回一个指向modnil指针吗?如果是这样,mod.Name()将会因为nil指针解引用而引发panic

参考资料:

Go编程语言规范接口类型

Go数据结构:接口

为什么我的nil错误值不等于nil?


这个代码的修订版本的输出是什么?

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
	}
}

huangapple
  • 本文由 发表于 2015年10月26日 09:09:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/33336998.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定