How can v == nil return false and reflect.ValueOf(v).IsNil() return true at the same time?

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

How can v == nil return false and reflect.ValueOf(v).IsNil() return true at the same time?

问题

这是一些代码:

var v interface{}
v = (*string)(nil)

// 反射显示它是 nil
val := reflect.ValueOf(v)
if val.IsNil() {
    fmt.Println("val 是 nil")
} else {
    fmt.Println("val 不是 nil")
}

// 这里显示它不是 nil
if v == nil {
    fmt.Println("v 是 nil")
} else {
    fmt.Println("v 不是 nil")
}

https://play.golang.org/p/apyPa4CNZ6

输出结果是:

val 是 nil

v 不是 nil

这是怎么可能的?v 是 nil 还是不是?

另外,如果你将前两行改为:

v := (*string)(nil)

那么输出明确表示变量是 nil。

我目前的项目中有一个接受 interface{} 类型参数的函数,我无法可靠地通过简单的 v == nil 来检查它是否为 nil。我希望避免使用 reflect 包。

英文:

Here's some code:

var v interface{}
v = (*string)(nil)

// Reflect says it is nil
val := reflect.ValueOf(v)
if val.IsNil() {
    fmt.Println("val is nil")
} else {
    fmt.Println("val is not nil")
}

// This says it is not nil
if v == nil {
    fmt.Println("v is nil")
} else {
    fmt.Println("v is not nil")
}

https://play.golang.org/p/apyPa4CNZ6

The output is:

> val is nil
>
> v is not nil

How is this possible? Is v nil or not?

Also, if you change the first two lines with

v := (*string)(nil)

then the output clearly states that the variable is nil.

Right now in my project I have a function that accepts a argument of type interface{} and I can't reliably check if it is nil with a simple v == nil. I would like to avoid using the reflect package.

答案1

得分: 4

来自golang.org:

> 在底层,接口由两个元素实现,一个是类型,一个是值。值被称为接口的动态值,是一个任意的具体值,而类型则是该值的类型。对于int值3,接口值包含了(int,3)的示意图。
>
> 只有当内部值和类型都未设置时,接口值才为nil,即(nil,nil)。特别地,nil接口将始终持有一个nil类型。如果我们将类型为int的nil指针存储在接口值中,无论指针的值如何,内部类型都将是int:(*int,nil)。因此,即使内部指针为nil,这样的接口值也将是非nil的。

你可以尝试使用fmt.Printf("(%v, %T)\n", v, v)。它会打印出(<nil>, *string)

当你将前两行改为v := (*string)(nil)时,v只是一个指针,而不是一个接口。

英文:

From golang.org:

> Under the covers, interfaces are implemented as two elements, a type
> and a value. The value, called the interface's dynamic value, is an
> arbitrary concrete value and the type is that of the value. For the
> int value 3, an interface value contains, schematically, (int, 3).
>
> An interface value is nil only if the inner value and type are both
> unset, (nil, nil). In particular, a nil interface will always hold a
> nil type. If we store a nil pointer of type *int inside an interface
> value, the inner type will be *int regardless of the value of the
> pointer: (*int, nil). Such an interface value will therefore be
> non-nil even when the pointer inside is nil.

You can try fmt.Printf(&quot;(%v, %T)\n&quot;, v, v). It prints (&lt;nil&gt;, *string).

When you change first two lines to v := (*string)(nil), v is just a pointer, not an interface.

huangapple
  • 本文由 发表于 2017年2月14日 12:23:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/42217839.html
匿名

发表评论

匿名网友

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

确定