Go基础--Map

Map

  • Map是一个拥有key value对的元素的无序集合,key的值是唯一的
  • Go里面的Map就是Hash Table的引用,是引用类型,类似Pointer和Slice

一、声明和初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 这样初始化默认是一个nil类型,没有引用任何散列表
var m map[string]int

fmt.Println(m == nil) // true

// 这样赋值就会出错
m["a"] = 1

// 初始化的时候,使用make
m = make(map[string]int)
fmt.Println(m == nil) // false

// 这种方式跟make的效果一样
m := map[string]int{}

// 可以初始化有默认值的map
commits := map[string]int{
"rsc": 3711,
"r": 2138,
"gri": 1908,
"adg": 912,
}

  • map的key需要是同一数据类型,map的value也需要是同一数据类型
  • Key是任何可比较类型的值(就是指可以用 == != < > <= >= 这些符号进行比较的值)
    • boolean, numeric, string
    • pointer,
    • channel,
    • interface types
    • structs or arrays that contain only those types.
  • Key类型不可以是以下的值
    • map
    • list
    • slices
    • functions
  • Value是任何类型的值

二、使用

2.1.基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// set and get
m["a"] = 66
i := m["a"]

// 如果key不存在,则返回value所属类型的默认值
// 比如int就是0, string就是空字符串
// 以下j == 0
j := m["b"]

// move entry, delete成功或者失败都不返回任何值
delete(m, "b")

// 获取map的长度
n := len(m)

// 测试一个key是否存在
// 如果不存在,i==0,ok==false
i, ok := m["b"]
// 仅仅检测key有没有,使用如下方式
_, ok := m["b"]


// 迭代
for key, value := range m {
fmt.Println("Key:", key, "Value:", value)
}


// 编译错误,map元素不是一个变量,不能取地址
// 原因是map的增长可能会导致已有的元素被重新散列到新的存储位置,这样地址就会变
_ = &m["a"]


2.2.顺序迭代

map的迭代是无序的,如果需要顺序迭代,要自己实现

1
2
3
4
5
6
7
8
9
10
11
import "sort"

var m map[int]string
var keys []int
for k := range m {
keys = append(keys, k)
}
sort.Ints(keys)
for _, k := range keys {
fmt.Println("Key:", k, "Value:", m[k])
}

因为已经确定了m的长度,所以初始化keys slice的时候,直接指定长度会更加高效

1
keys := make([]int, 0, len(m))

2.3.判断两个map是否相同

不能直接判断两个map是否相同,需要自己实现

1
2
3
4
5
6
7
8
9
10
11

func compareMapEqual (x, y map[string]int) bool {
if len(x) != len(y):
return false
for k, xv := range(x){
if yv, ok := y[k]; !ok || xv != yv{
return false
}
}
return true
}

2.4.用map实现set

https://juejin.cn/post/6844903857101733902
https://geektutu.com/post/hpg-empty-struct.html

go中没有set类型,可以借助map key唯一的特点实现

如果使用bool作为value类型,会占用1个字节,100w条数据就会多占1MB左右的空间,使用空struct就会更节约内存

1
unsafe.Sizeof(struct{}{})  == 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

type void struct{}
var v void

set := make(map[string]void)

// set
set["a"] = v

// get
_, ok := set["b"]

// delete
delete(set, "b")


// len
len(set)

// for loop
for k := range set{
fmt.Println(k)
}