nil是go语言中的预先定义的标识符,不是关键字或保留字!
很多类型的默认值是nil,当然一些基类型的默认值不是nil,这个需要注意,下面是一些初始化值:
布尔类型的零值:false
数值类型的零值:0
字符串类型的零值:空字符串""
除此之外其它类型的默认值为nil,代表下面这些类型的零值:
指针类型(包括unsafe中的)
map类型、slice类型、function类型、channel类型、interface类型
比如整型和整型指针 :
var n1 *int
fmt.Printf("%p,%#v\n", n1, n1)
//0x0,(*int)(nil)
var n2 int
fmt.Printf("%p,%#v\n", &n2, n2)
//0xc000122078,0
我们可以看到,第一个整型指针的初始指针是nil指针或说无效指针,第二个就是常见的整型,取地址可以看到是正常的有效地址,默认初始化为0
如果我们分别对它们做一个自增的操作,看下会发生什么事情?
var n1 *int
*n1++
fmt.Printf("%p,%#v\n", n1, n1)
/*
发生异常: panic
"runtime error: invalid memory address or nil pointer dereference"
*/
var n2 int
n2++
fmt.Printf("%p,%#v\n", &n2, n2)
//0xc00001a098,1
第一个就会报错了,因为是nil指针,nil的值,地址方面是无效地址,值不是整形类型的值,所以肯定没法做加法操作,而第二的整型类型当然是没有问题的,可以累加等操作。
虽然存在各种不同的指针类型,但是初始化的指针都是一样的,如下:
var str *string
fmt.Printf("%p,%#v\n", str, str) //0x0,(*string)(nil)
var str1 *[]string
fmt.Printf("%p,%#v", str1, str1) //0x0,(*[]string)(nil)
可以看到他们虽然类型不一样,但是其指针都是0x0,值都是nil
new和make看起来操作方面是差不多,确实很多时候表面来看也都是没多大区别,比如:
i1 := new(int)
*i1 = *i1 + 3
fmt.Printf("%#v,%#v\n", i1, *i1) //(*int)(0xc0000a6058),3
m1 := make(map[string]string)
m1["name"] = "寅恪光潜"
fmt.Printf("%p,%#v\n", m1, m1) //0xc0000b6480,map[string]string{"name":"寅恪光潜"}
都是可以初始化然后进行操作,那为什么会多此一举的要多一个方法呢?其实原理上还是有很大区别,我们来看下这个整型指针的初始化操作:
i := new(*int)
fmt.Printf("%#v,%#v\n", i, *i)
//(**int)(0xc0000c4020),(*int)(nil)
可以看到初始化为nil指针与nil值,这个时候做自增等操作,我们知道那肯定是报错的。
i := new(*int)
**i++
fmt.Printf("%#v,%#v\n", i, *i)
/*
发生异常: panic
"runtime error: invalid memory address or nil pointer dereference"
*/
但是通过make初始化的nil可以将他们初始化成空,地址是有效地址,我们来看下:
m := make(map[string]string)
fmt.Printf("%p,%#v\n", m, m)//0xc000072510,map[string]string{}
m["name"] = "寅恪光潜"
fmt.Printf("%p,%#v\n", m, m)//0xc000072510,map[string]string{"name":"寅恪光潜"}
上面我们可以看到make初始化的类型没有出现nil指针以及nil值对吧。
注意:make只针对map,slice,channel这三个类型做初始化。
Slice := make([]int, 3, 5)
fmt.Printf("%p,%#v,%v,%v\n", Slice, Slice, len(Slice), cap(Slice)) //0xc00000e420,[]int{0, 0, 0},3,5
Map := make(map[string]int, 5)
fmt.Printf("%p,%#v,%v\n", Map, Map, len(Map)) //0xc0000725a0,map[string]int{},0
Map["h1"] = 110
fmt.Printf("%p,%#v,%v\n", Map, Map, len(Map)) //0xc0000725a0,map[string]int{"h1":110},1
Chan := make(chan int, 5)
fmt.Printf("%p,%#v,%v\n", Chan, Chan, len(Chan)) //0xc000102000,(chan int)(0xc000102000),0