英文:
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{}
变量想象成一个由两个字段组成的结构体:一个是类型,另一个是数据([]int
和nil
)。实际上,在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!
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论