不能不注意的nil
nil的本质
官方文档:
nil 是一个预先声明的标识符,表示指针、通道、函数、接口、map或slice 类型的零值。
// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type
// Type is here for the purposes of documentation only. It is a stand-in
// for any Go type, but represents the same type for any given function
// invocation.
type Type int
由此可见nil的值就是默认初始化的0,nil实质是一个代表了0的变量
nil的作用
仅仅告诉编译器如何去初始化这一类型的数据,不一定不占用内存,不用把它单纯地当做java,c++里面的null
怎么来论证呢?slice大家知道吧,slice的原型就是一个struct,你说struct的0值是啥意思呢?所以可以大胆给出结论:nil是给编译器用来初始化(pointer, channel, func, interface, map, or slice type)的零值情况的,具体要不要占用内存各自要看实际情况
下面我看看slice的原型: (为了便于强转我们命名为slice2)
type slice2 struct {
pointer unsafe.Pointer
len int
cap int
}
func main() {
var s []int=nil
fmt.Printf("%p\n", s) //0x0
fmt.Printf("%p\n", &s) //0xc000004078 举例
fmt.Println("size:",unsafe.Sizeof(s)) //这里是会占用内存的
p:=unsafe.Pointer(&s)
ps:=(*slice2)(p)
ps.len=12
fmt.Println(len(s)) //被改变了....,说明s其结果如上,且是占用内存的
fmt.Printf("%p\n",ps.pointer)
}
结果如下:
0x0
0xc000004078
size: 24
12
0x0
Ps:empty slice和nil slice的区别在于,数组指针是否赋值了,所有的empty数组指针固定执行一个空数组地址
容易我们可以用上面的方法论证其他情况,但注意map是hmap的指针语法糖,下面举例看看interface
type eface struct { // empty inteface的大概原型
_type unsafe.Pointer
data unsafe.Pointer
}
func testInterface() {
var pint interface{} =nil
p := unsafe.Pointer(&pint)
ps := (*eface)(p)
temp:=33
ps._type = unsafe.Pointer(&temp)
fmt.Println(pint == nil) //false
}
func main() {
testInterface()
}
结论:
nil是给编译器用来初始化(pointer, channel, func, interface, map, or slice type)的零值情况的,具体要不要占用内存各自要看实际情况
初始化零值的情况,不能简单地说不会占用内存,也不要把它当做空指针来看待.