定义与操作

定义与操作

我们看下面的代码,map 的读取和设置也类似 slice 一样,通过 key 来操作,只是 slice 的 index 只能是 int 类型,而 map 多了很多类型,可以是 int,可以是 string 及所有完全定义了 ==!= 操作的类型。

// 声明一个 key 是字符串,值为int的字典,这种方式的声明需要在使用之前使用make初始化
var numbers map[string]int

// 另一种 map 的声明方式
numbers := make(map[string]int)
numbers := map[string]int{}

// map 中的默认值为 0
numbers["one"] = 1//赋值
numbers["ten"] = 10 //赋值
numbers["three"] = 3

fmt.Println("第三个数字是: ", numbers["three"]) // 读取数据
// 打印出来如:第三个数字是: 3

这个 map 就像我们平常看到的表格一样,左边列是 key,右边列是值,使用 map 过程中需要注意的几点:

  • map 是无序的,每次打印出来的 map 都会不一样,它不能通过 index 获取,而必须通过 key 获取
  • map 的长度是不固定的,也就是和 slice 一样,也是一种引用类型
  • 内置的 len 函数同样适用于 map,返回 map 拥有的 key 的数量
  • map 的值可以很方便的修改,通过 numbers["one"]=11 可以很容易的把 key 为one的字典值改为11
  • map 和其他基本型别不同,它不是 thread-safe,在多个 go-routine 存取时,必须使用 mutex lock 机制

特别注意的是,map 也是一种引用类型,如果两个 map 同时指向一个底层,那么一个改变,另一个也相应的改变:

m := make(map[string]string)
m["Hello"] = "Bonjour"
m1 := m
m1["Hello"] = "Salut"// 现在m["hello"]的值已经是Salut了

取值与遍历

对 map 取值,返回两个参数,第二个参数为 bool 值,标志 key 是否存在于 map 中:

s := m["hello"] // 如果key不存在,s为对应类型的零值
s, ok := m["hello"] // 如果key不存在, ok为false,反之为true
_, exists := m["hello"] // 用来确定key是否存在

map 的零值为 nil。对于 map 的零值得读取,不会出错,但是写入则会引发 panic,例如:

func main() {
	var m map[string]string
	fmt.Println(m["hello"])
	m["hello"] = "world"
}

// error
panic: assignment to entry in nil map

goroutine 1 [running]:
main.main()
	/tmp/main.go:10 +0xee
exit status 2

操作

删除

通过delete删除 map 的元素:

// 初始化一个字典
rating := map[string]float32{"C":5, "Go":4.5, "Python":4.5, "C++":2 }

// map有两个返回值,第二个返回值,如果不存在key,那么ok为false,如果存在ok为true
csharpRating, ok := rating["C#"]
if ok {
  fmt.Println("C# is in the map and its rating is ", csharpRating)
} else {
  fmt.Println("We have no rating associated with C# in the map")
}

delete(rating, "C")// 删除key为C的元素