map

map实现方式

go语言中map使用hash(散列表)实现

定义方法

1
2
3
4
5
6
7
8
// 声明一个 map 变量,其值为nil,(m1==nil)为true
var m1 map[int]int

// 创建一个空map (可在{}中填写map中的元素)
m2 := map[int]int{}

// 创建一个空map
m3 := make(map[int]int)

mapkey类型限制

map使用hash表存储实现,key类型必须可比较相等。
mapkey类型必须不为function,slice,map,在定义时,如果使用这些类型会报错。
struct类型也可作为key类型,但如果使用带有这些类型属性的struct不可以作为key。可能编译不会报错,但运行时会报错。

map使用错误的key类型报错

Map操作

map长度

获取长度方法:len(map)

访问

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import "fmt"

func main() {

m := map[int]interface{}{
0: 0,
1: 2,
2: 4,
3: 6,
5: nil,
}
// 直接访问不存在的元素
m4v := m[4]
fmt.Println(m4v)
// 使用ok参数接收是否取得正确的值
m4v, ok := m[4]
fmt.Println(m4v, ok)
// 使用ok参数接收是否取得正确的值
m5v, ok := m[5]
fmt.Println(m5v, ok)
}

测试结果:

1
2
3
<nil>
<nil> false
<nil> true

注意:

  1. 不使用ok参数接收是否取得值时,如果不存在key值对应的val,则返回对应类型的空:int返回0string返回"",引用类型返回nil等。
  2. 使用ok参数可以通过判断ok知道map中是否存在key
  3. 不使用ok时可能存在的问题,如上代码,m[4]不存在于map中,取得结果为nilm[5]存在于map中,其本身对应的值为nil所以取得结果也为nil,这种情况下可能会存在问题

遍历

测试代码

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

import "fmt"

func main() {

m := map[int]int{
0: 0,
1: 2,
2: 4,
3: 6,
}
for k, v := range m {
fmt.Println(k, v)
}
}

注意:

每次运行程序输出顺序可能不一致,map不能保证遍历的顺序性

删除元素

删除方法 delete

测试代码

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{
0: 0,
1: 2,
2: 4,
}
delete(m, 0)
_, ok := m[0]
fmt.Println(ok)
// 测试删除不存在的元素,不会报错
delete(m,5)
}

测试结果

输出:false

安全map——sync.Map

普通map类型在只读的情况下是线程安全的,但同时读写时非线程安全。

普通线程安全性

普通map线程安全测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

func main() {

m := make(map[int]int)
// 无限向map写数据
go func() {
for {
m[1] = 1
}
}()
// 无限从map读数据
go func() {
for {
_ = m[1]
}
}()
// 让主线程不退出,并发程序后台执行
for true {
_ = 1
}
}

测试结果:报错

1
fatal error: concurrent map read and map write

sync.Map

操作

添加元素

方法:Store(key,val)LoadOrStore(key,val)

  1. Store(key,val)方法,将key:val对存入map中;
  2. LoadOrStore(key,val)方法,返回值有两个 (val,ok)val表示在mapkey对应的值(如果已存在,则为原map中的值,如果不存在,则先将key:val对存入map,再返回val);ok表示map中是否已存在key值及其对应的val

删除元素

方法: Delete(key)

删除mapkey及其对应的val

获取元素

方法: Load(key)LoadOrStore(key,val)

  1. 直接调用Load方法,返回值有两个(val,ok),值以及是否存在
  2. LoadOrStore方法在添加元素部分已解释

遍历元素

方法: Range(f func(key, value interface{}) bool)

参数是一个函数,在函数中执行遍历操作