Go语言的字典类型是由一个哈希表特定实现的,在这个实现中,键和元素最大不同在于,前者的类型是受限的,后者却可以是任何类型。
在哈希表中查找某个键值对应的那个元素值,需要先把键值作为参数传给这个哈希表,哈希表会先用哈希函数把键值转换为哈希值。哈希值通常是一个无符号的整数,一个哈希表会持有一定数量的桶(bucket,哈希桶),这些哈希桶会均匀地存储其所属哈希表收纳的那些键值对。哈希表会先用这个键的哈希值的低几位去定位到一个哈希桶,然后再到这个哈希桶中查找这个键,由于键值对是捆绑在一起存储的,所以一旦找到了键,就一定能找到对应的元素值。随后哈希表就会把相应的元素值作为结果返回。
1. 字典的键类型不能是哪些类型?
Go语言规范规定,在键类型的值之间必须可以施加操作符==和!=,即键类型的值必须要支持判等操作。由于函数类型、字典类型、切片类型不支持判等操作,所以字典的键类型不能是这些类型。
不建议使用高级数据类型(数组、接口、结构体)作为字典的键类型,它们的值求哈希较慢,并且它们的值中存在变数(可以修改其中的元素值),还需要对其内部元素类型进行判断。
如键的类型是数组类型,那么还要确保该类型的元素类型不是函数类型、字典类型或切片类型。
2. 应该优先考虑哪些类型作为字典的键类型?
求哈希和判等操作的速度越快,对应的类型就越适合作为键类型。
宽度(单个值需要占用的字节数,如bool、int8的字节宽度都是1)越小的类型速度通常越快。对高级类型,如数组类型的值求哈希实际上是依次求得它的每个元素的哈希值并进行合并。
因此优先选用数值类型和指针类型作为字典的键类型。
3. 在值为nil的字典上执行读操作会成功吗?那写操作呢?
由于字典是引用类型,所以当我们仅声明而不初始化一个字典类型的变量的时候,它的值会是nil。
除添加键值对,在一个值为nil的字典上做任何操作都不会引起错误。当试图在一个值为nil的字典中添加键值对时,会抛出panic。