【Go语言学习】03-复合数据类型

本文介绍go的另一个复合类型 map

什么是map类型

map 是 Go 语言提供的一种抽象数据类型,它表示一组无序的键值对。在后面的讲解中,我们会直接使用 key 和 value 分别代表 map 的键和值。而且,map 集合中每个 key 都是唯一的:

和切片类似,作为复合类型的 map,它在 Go 中的类型表示也是由 key 类型与 value 类型组成的,就像下面代码:

1
map[key_type]value_type

key 与 value 的类型可以相同,也可以不同:

1
2
map[string]string // key与value元素的类型相同
map[int]string // key与value元素的类型不同

map 类型对 value 的类型没有限制,但是对 key 的类型却有严格要求,因为 map 类型要保证 key 的唯一性。Go 语言中要求,key 的类型必须支持“==”和“!=”两种比较操作符。但是,在 Go 语言中,函数类型、map 类型自身,以及切片只支持与 nil 的比较,而不支持同类型两个变量的比较。如果像下面代码这样,进行这些类型的比较,Go 编译器将会报错:

1
2
3
4
5
6
7
8
9
s1 := make([]int, 1)
s2 := make([]int, 2)
f1 := func() {}
f2 := func() {}
m1 := make(map[int]string)
m2 := make(map[int]string)
println(s1 == s2) // 错误:invalid operation: s1 == s2 (slice can only be compared to nil)
println(f1 == f2) // 错误:invalid operation: f1 == f2 (func can only be compared to nil)
println(m1 == m2) // 错误:invalid operation: m1 == m2 (map can only be compared to nil)

所以函数类型、map 类型自身,以及切片类型是不能作为 map 的 key 类型的。

map 变量的声明和初始化

方法一:使用复合字面值初始化 map 类型变量。

1
2
3
4
5
6
7
type Position struct { x float64 y float64}

m := map[Position]string{
{29.935523, 52.568915}: "school",
{25.352594, 113.304361}: "shopping-mall",
{73.224455, 111.804306}: "hospital",
}

方法二:使用 make 为 map 类型变量进行显式初始化。

1
2
m1 := make(map[int]string) // 未指定初始容量
m2 := make(map[int]string, 8) // 指定初始容量为8

map的基本操作

插入

查找:

1
2
m := make(map[string]int)
v := m["key1"]

当我们尝试去获取一个键对应的值的时候,如果这个键在 map 中并不存在,我们也会得到一个值,这个值是 value 元素类型的零值。所以go采用 comma ok的方式判断key对应的value值存在与否

1
2
3
4
5
6
7
m := make(map[string]int)
v, ok := m["key1"]
if !ok {
// "key1"不在map中
}

// "key1"在map中,v将被赋予"key1"键对应的value

删除:

只能使用delete函数,即使key值不存在,函数执行也不会失败

1
2
3
4
5
6
7
8
m := map[string]int {
"key1" : 1,
"key2" : 2,
}

fmt.Println(m) // map[key1:1 key2:2]
delete(m, "key2") // 删除"key2"
fmt.Println(m) // map[key1:1]

遍历:

遍历 map 的键值对只有一种方法,那就是像对待切片那样通过 for range 语句对 map 数据进行遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import "fmt"

func main() {
m := map[int]int{
1: 11,
2: 12,
3: 13,
}

fmt.Printf("{ ")
for k, v := range m {
fmt.Printf("[%d, %d] ", k, v)
}
fmt.Printf("}\n")
}

map的底层实现

待补充