当将nil切片传递给接口时,它不是nil!为什么?(golang)

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

nil slice when passed as interface is not nil! Why? (golang)

问题

这两个函数的输出有什么区别呢?

这是因为在Go语言中,切片类型([]int)是引用类型,而接口类型(interface{})是值类型。

在函数yes中,参数thing是切片类型,当传入nil时,切片被初始化为一个空切片,但它仍然指向一个有效的内存地址。因此,thing == nil的比较结果为false

而在函数no中,参数thing是接口类型,当传入nil时,接口被初始化为一个空接口,它的动态值和动态类型都是nil。因此,thing == nil的比较结果为true

所以,这两个函数的输出结果不同。

英文:

See this playground: http://play.golang.org/p/nWHmlw1W01

package main

import "fmt"

func main() {
	var i []int = nil
	yes(i) // output: true
	no(i)  // output: false
}

func yes(thing []int) {
	fmt.Println(thing == nil)
}

func no(thing interface{}) {
	fmt.Println(thing == nil)
}

Why the difference in output between the two functions?

答案1

得分: 17

诚然,这有点奇怪,但是有一个解释。

interface{}变量想象成一个由两个字段组成的结构体:一个是类型,另一个是数据([]intnil)。实际上,在Go运行时中它看起来就是这样的。

struct Iface
{
    Itab*   tab;
    void*   data;
};

当你将nil切片传递给yes函数时,只有nil作为值被传递,所以你的比较可以简化为nil == nil

而调用no函数时,会自动将你的变量包装在interface{}类型中,调用变成了类似于no(interface{[]int, nil})的形式。所以在no函数中的比较可以看作是interface{[]int, nil} == nil,在Go中这个比较结果是false。

实际上,这个问题在Go FAQ中有解释。

英文:

Admittedly, it's somewhat of a quirk, but there's an explanation for it.

Imagine an interface{} variable as a struct composed of two fields: one is the type and another is the data. ([]int and nil). Actually, it looks just like that in the Go runtime.

struct Iface                                                                                                                   
{                                                                                                                              
    Itab*   tab;                                                                                                               
    void*   data;                                                                                                              
};   

When you pass your nil slice to yes, only nil is passed as the value, so your comparison boils down to nil == nil.

Meanwhile, calling no automatically wraps your variable in an interface{} type and the call becomes something akin to no(interface{[]int, nil}). So the comparison in no could be seen as interface{[]int, nil} == nil, which turns out to be false in go.

The issue is actually explained in the Go FAQ.

答案2

得分: 1

添加到@justinas的答案中,如果您需要比较interface{}值内部的值,可以使用reflect.ValueOf.IsNil()方法,该方法将报告interface{}内部的值是否为nil。

func main() {
	var a []int = nil
	var ai interface{} = a

	r1 := a == nil // true
	r2 := ai == nil // false,interface不为nil

	vo := reflect.ValueOf(ai).IsNil() // true,interface内部的值为nil!
}
英文:

To add to @justinas' answer, if you need to compare the value inside the interface{} value, you can use reflect.ValueOf.IsNil() method which would report if value inside the interface{} is nil.

func main() {
	var a []int = nil
	var ai interface{} = a

	r1 := a == nil // true
	r2 := ai == nil // false, interface is not nil

	vo := reflect.ValueOf(ai).IsNil() // true, value inside interface is nil!
}

huangapple
  • 本文由 发表于 2014年1月30日 23:37:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/21460787.html
匿名

发表评论

匿名网友

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

确定