golang map相关

map

map键值对的数据结构,在go中map的key具有很大的灵活度,你可以用一切可以进行对比操作(==,!=)的类型来当key例如string,int,指针等,甚至与当你需要时你也能够用一个struct来当作key(struct内的所有变量类型都应当能够对比)。值得关注的是map是无序的当你对一个map进行增强for循环迭代时,每次的顺序都是随机的,需要额外的代码进行有序的循环(最开始增强for循环迭代map是有序的,不过出于依赖考虑被go官方改为了无序迭代)。

map的初始化

golang里map的初始化非常简单:
声明map:var map1 map[type]type
若不进行初始化map1默认nil,长度为0;
使用内置函数make进行map的初始化:
当key是基础类型时:

map1 := make(map[string]bool)
map1["BangBrother"] = true
map1["Chopin"] = false
fmt.Println(map1)

输出:

map[BangBrother:true Chopin:false]

当key是struct时:

	type student struct {//声明struct
		name   string
		number int64
	}
	s1 := student{//初始化struct
		name:   "1",
		number: 1,
	}
	studentMap := make(map[student]int)
	//可以直接用已存在的
	studentMap[s1] = 1
	//也可以新建一个
	studentMap[student{
		name:   "2",
		number: 2,
	}] = 2
	fmt.Println(studentMap)

输出:

map[{1 1}:1 {2 2}:2]

在student这个struct内变量不能出现数组,切片这种不能直接对比的类型,否则编译器会报错:invalid map key type 结构体名
在对比struct时是将struct内的所有变量的值一一对比一遍,有一个不同则为不同的key否则就是同一个key,跟student的引用地址无关。

	s1 := student{
		name:   "1",
		number: 1,
	}
	s2 := student{
		name:   "1",
		number: 1,
	}
	fmt.Printf("s1:%p\n", &s1)
	fmt.Printf("s2:%p\n", &s2)
	studentMap := make(map[student]int)
	studentMap[s1] = 1
	studentMap[s2] = 2
	fmt.Println(studentMap)

结果:

s1:0xc00009e440
s2:0xc00009e460
map[{1 1}:2]

可以看的出来即使是不同的student只要值相同就能被判断为相同key将其值覆盖掉。

map的迭代

在go语言中没有现成的循环让你获得有固定顺序的map,但是实现固定顺序循环也是非常简单的一件事。
当你只在乎里面的值而不在乎顺序时:

map1 := make(map[string]int)
map1["chopin"] = 23
map1["bang"] = 24
map1["brother"] = 25
for key, value := range map1 {
	fmt.Println(key, value)
}

此时打印出来的结果顺序将是随机的

1.                 2.
chopin 23          brother 25               
bang 24            chopin 23                
brother 25         bang 24

若想要每次程序运行时具有固定的顺序,需要额外维护一个存放有key的数据结构:

	keys := make([]string, len(map1))
	count := 0
	for key := range map1 {
		keys[count] = key
		count++
	}
	for _, key := range keys {
		fmt.Println(key, map1[key])
	}

map的基本操作

判断某个key是否存在:value, ok := map1[key]
这里的ok如果是true就代表该key存在,如果是false则不存在,且value会赋值nil。
根据key删除某个map记录可以使用内置函数delete:

delete(map1, "chopin")

此处并不需要赋值,若map1不存在该key也不会报错,无事发生。

map的并发安全

map在并发情况下是不安全的,需要我们给与额外的支持,通常可以用sync.RWMutex这个库来解决并发的安全性问题。
读取时可以用读锁:

	var lock sync.RWMutex
	lock.RLock()
	temp:=map1["chopin"]
	lock.RUnlock()

对map设置值时可以用写锁:

	lock.Lock()
	map1["chopin"] = 100
	lock.Unlock()

当然我们还可以直接用并发安全版本的map->sync.Map,值得注意的是sync.Map并不需要用make来进行初始化,直接调用里面的方法就好了。

	var syncMap sync.Map
	syncMap.Store("chopin", 123)//增加数据
	syncMap.Store("bang", 100)
	//为map中的每个键和值调用func(k,v interface{})bool
	//当方法返回false时跳出循环,返回true继续循环
	syncMap.Range(func(key interface{}, value interface{}) bool {
		fmt.Println(key, value)
		return true
	})
	fmt.Println(syncMap.Load("bang"))//通过key获取value
	syncMap.Delete("chopin")//通过key删除map数据
	fmt.Println(syncMap.Load("chopin"))//若不存在返回nil,false

输出结果:

chopin 123
bang 100
100 true
<nil> false

需要注意的是Range(func(k,v interface{})bool)这个函数每个key只会执行一遍,但如果同时存储或删除任意键的值,则Range可以反映Range调用期间该键的任何映射。该函数的结果顺序和增强for循环一样是随机的。
如果对更多并发操作感兴趣可以去看看别人的文档。此处仅介绍map。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值