Go语言的字典类型其实就是一个哈希表的特定实现。字典的键的类型是受限的,元素的类型能够是任意类型。算法
典的
键-元素对
的增删改查的操做,就是哈希表的映射过程。数组
以查找为例:安全
哈希值一般是一个无符号的整数。一个哈希表会持有必定数量的哈希桶。并发
因为键-元素对老是被捆绑在一块儿存储的,因此一旦找到了键,就必定能找到对应的元素值。函数
回答:字典的键不能是函数类型,字典类型,切片类型。性能
那么,剩下的:基本数据类型,(int系列,float系列,string,复数),数组,结构体,指针,接口等均可以做为键类型。ui
Go语言规范规定:在键类型的值之间必须能够施加操做符==
和!=
。也就是说键类型的值必需要支持判等操做。指针
求哈希和判等的速度越快,对应的类型就越适合做为键类型。code
宽度越小的类型求哈希的速度一般越快。好比布尔类型,整数类型,浮点数类型,复数类型和指针类型。接口
对于字符串类型,因为它的宽度是不定的,因此要看它的值的具体长度,长度越短,求哈希越快
类型的宽度是指它的单个值须要占用的字节数。好比,bool,int8,uint8类型的一个值须要占用的字节都是1个。所以宽度就都是1。
对于高级类型:
数组:对数组求哈希其实是依次求得它的每一个元素的哈希值并进行合并,因此速度就取决于它的元素类型以及它的长度。
结构体:对结构体类型的值求哈希值实际上就是对它的全部字段求哈希值并进行合并。因此关键在于它的各个字段的类型和字段的数量。
接口:对于接口类型,具体的哈希算法由值的实际类型决定。
不建议使用高级数据类型做为字典的键类型。优先选用数值类型和指针类型。一般状况下类型的宽度越小越好。若是非要选择字符串类型的话,最好对键值的长度进行额外的约束。
一个是由于对他们求哈希值和判等的速度较慢,还由于他们的值中存在变数。好比,改变数组中任意一个元素,数组的哈希值就变了。
虽然结构体能够经过控制其中字段的访问权限,来防止外界修改它。
把接口类型做为键类型最危险。
因为字典是引用类型,当咱们仅仅声明而不初始化一个字典类型的变量的时候,这个变量的值就是nil。
对这个值为nil的字典进行添加键-元素对,会引起错误。其余操做没有问题。
非原子操做须要加锁,map操做不是并发安全的,map并发读写须要加锁。
判断一个操做是不是原子的,可使用go run race
命令作数据的竞争检测。经过 sync.Map 或本身使用sync.RWMutex本身实现并发互斥逻辑