深入理解 Go 语言并发 map 安全使用

        对于哈希表(hash table) 这种数据结构,它实现的就是 key-value 之间的映射关系,主要提供的方法包括 Add、Lookup、Delete 等。因为哈希表是一种基础的数据结构,每个 key 都会有一个唯一的索引值,通过索引可以很快地找到对应的值,所以使用它进行数据的插入和读取是很快的。Go 语言本身就内建了这样一个数据结构,也就是 map 数据类型。

1. 线程安全的 map

        Go 语言内建的 map 类型如下:

map[k]V

        其中,key 类型的 K 必须是可比较的(comparable),也就是可以通过 == 和 != 操作符进行比较;V 的值和类型无所谓,它可以是任意类型,或者为 nil。在 Go 语言中,bool、整数、浮点数、复数、字符串、指针、Channel、接口都是可比较的,包含可比较元素的 struct 和数组也是可比较的,而 sliece、map、函数值都是不可比较的。

        那么,上面这些可比较的数据类型都适合作为 map 的 key 的类型吗?答案是否定的。在通常情况下,我们会选择内建的基本类型,比如整数、字符串作为 key 的类型,因为这样最方便,值不可变,也不容易出错。而使用 struct 作为 key 的类型,如果 struct 的某个字段值被修改了,那么在查询 map 时将无法获取它添加的值。

type mapKey struct {
	key int
}

func mail() {
	var m = make(map[mapKey]string)
	var key = mapKey{10}

	m[key] = "hello"
	fmt.Printf("m[key]=%s\n", m[key])

	// 修改 key 的字段值后再次查询map,将无法获取刚才添加的值
	key.key = 100
	fmt.Printf("再次查询m[key]=%s\n", m[key])
}

        那该怎么办呢?如果使用 struct 作为 key 的类型,则要保证 struct 对象在逻辑上是不可变的,这样才能保证 map 的逻辑没有问题。以上就是在选择 key 类型时需要注意的地方。

         接下来,我们看一下使用 map[key] 函数时需要注意的一个知识点。在 Go 语言中, map[key] 函数的返回结果可以是一个值,也可以是两个值,这是容易让人迷惑的地方。原因在于:如果获取一个不存在的 key 对应的值,则会返回零值。为了区分真正的零值和 key 不存在这两种情况,可以根据第二个返回值来判断,如下面代码:

func main(){
	var m = make(map[string]int)
	m ["a"] = 0
	fmt.Printf("a=%d;b=%d\n",m["a"],m["b"])
	
	av,aexisted := m["a"]
	bv,bexisted := m["b"]
	fmt.Printf("a=%d,existed:%t;b=%d,existed:%t\n",av,aexisted,bv,bexisted)
}

        将对 map 的遍历故意设置成无序的&#

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mindfulness code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值