我们知道make函数用来初始化slice,map,以及chan;而一个slice,map,以及chan必须先被初始化才能使用的。
先看一个slice的使用例子:
1 package main
2
3 import (
4 "fmt"
5 )
6
7 func main() {
8 var s []string
9 fmt.Printf("len=%d cap=%d, %v\n", len(s), cap(s), s)
10
11 s = append(s, "aaa")
12 fmt.Printf("len=%d cap=%d, %v\n", len(s), cap(s), s)
13 }
你觉得这个程序能不能运行?
$ go build && ./main
len=0 cap=0, []
len=1 cap=1, [aaa]
有没有一点点诧异:变量s只是声明了一个slice类型,并没有进行初始化(make),这就直接被访问使用了,没有任何问题报出来,这怎么回事呢?
答案是,声明了一个slice,而没有被初始化,那么只是表明这个slice变量的值是nil,但是这个变量的类型信息还是完美的。任何操作如果能够接受nil作为参数,那么这个操作是能够成功进行的。
加一行代码:
1 package main
2
3 import (
4 "fmt"
5 )
6
7 func main() {
8 var s []string
9
10 if s == nil { fmt.Printf("s is nil\n") }
11
12 fmt.Printf("len=%d cap=%d, %v\n", len(s), cap(s), s)
13
14 s = append(s, "aaa")
15 fmt.Printf("len=%d cap=%d, %v\n", len(s), cap(s), s)
16 }
再次运行
$ go build && ./main
s is nil
len=0 cap=0, []
len=1 cap=1, [aaa]
- 第10行,我们看到打印出来s是nil值。
- 第12行,len()和cap()支持参数为nil的情况,返回值为0
- 第14行,append()也接受第一个参数为nil的情况,返回一个新的slice对象。
因为上述函数都接受nil作为参数处理,才导致这段代码正常运行。而如果碰到函数不接受nil作为输入,则必然会出错。
如何初始化slice:
方法1:用make
var s1 []string = make([]string, 0)
var s2 []string = make([]string, 1)
var s3 []string = make([]string, 20)
方法2:静态显式初始化
var s1 []string = []string{}
var s2 []string = []string{"aa"}
var s3 []string = []string{"aa", "bb", "cc"}
var s4 = []string{}
var s5 = []string{"aa"}
var s6 = []string{"aa", "bb", "cc"}
s7 := []string{}
s8 := []string{"aa"}
s9 := []string{"aa", "bb", "cc"}
需要注意的是 []string{}
这种方法,初始化成一个大小为0的slice,此时变量(s == nil)已经不成立了,但是s的大小len(s)还是等于0。实际上 []string{} == make([]string, 0)
。
map和chan的概念也是一样的。
例子1
package main
import (
"fmt"
)
func main() {
var m map[string]string
var n = m["AA"]
fmt.Println(n)
}
编译运行
$ go build && ./main
$
例子2
package main
import (
"fmt"
)
func main() {
var m map[string]string
for k, v := range m {
fmt.Println(k, v)
}
}
编译运行
$ go build && ./main
$
例子3:
package main
import (
"fmt"
)
func main() {
var m map[string]string
m["A"] = "a"
fmt.Println(len(m))
}
编译运行
$ go build && ./main
panic: assignment to entry in nil map
goroutine 1 [running]:
main.main()
/.../go/src/testnew/main.go:10 +0x59
在这三个例子中都定义了一个nil的map对象;而在例子1和例子2中读取map,即使map为nil,读的操作也都能成功返回,在例子3中是一个写操作,我们就可以看到写操作不允许map对象对nil,运行出错。