我们知道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{}[]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,运行出错。