Operations and constraints on dictionaries


1. Dictionary definitions


The advanced data types in the arrays and slicing containers we touched on earlier are containers for a single element. They store elements consecutively or with interlocking Pointers.
The dictionary stores not a single set of values, but a set of key-value pairs. The dictionary type of Go language is implemented in a hash table, and its key type is limited, while the value can be any type.


2. Storage and query methods of hash tables
To query an element in a hash table, you first need to pass the key value as an argument to the hash table. The hash table uses a hash function to convert the key value into a hash value, which is usually an unsigned integer. A hash table holds a number of buckets that evenly store key-element pairs.
And then the hash table uses the lower bits of the hash value of that key to locate a hash bucket, and then it goes to the hash bucket and looks for that key. Finding this key is equal to finding the element value.
The hash table then returns the result of the element value, and the process of adding, deleting, and changing the hash table is the same.


3. What types of dictionary key types cannot be


Go dictionary types cannot be function types, dictionary types, or slice types. Key type values in go must support equal operations. Because these three types do not support equal operations, the key types of dictionary types cannot be of these types.
Even if you set the key type to the interface type when the dictionary is initialized and then set the map key type to one of these three, it will not fail at compile time, but will throw a panic when the program runs. The later a program breaks, the more expensive it will be to fix, so don’t set the dictionary’s key type to any interface type.
Example:
package main


import (
“fmt”
)


var test = map[interface{}]int{
“a”: 1,
“[]int{2}”: 2,
3:3,
}


func main() {
FMT.Printf(“%v”, test[[]int{2}]) // does not generate errors at compile time, and does not generate errors directly from FMT.Printf(“%v”, test)
}
If the key type is array, make sure the array type cannot be function, dictionary, or slice. In a hash table, each hash bucket stores the hash values of all the keys it contains. Go solves the hash collision problem by matching the hash values of the key values with those hash values, and then comparing them with the key values themselves if they are equal. Because key values are to be compared, the key value type must be able to support equal operations.


4. Which types should be preferred as dictionary key types


The time spent in mapping dictionary queries is spent converting key values to hash values and comparing the key values to values in the hash bucket. Therefore, the faster these two operations are, the more suitable the corresponding type will be as a key type.
Go has a set of hash and judgment algorithms for all primitive types, pointer types, and array types, struct types, and interface types. In the case of hash summation, types with smaller widths are usually faster, and strings with shorter lengths are faster because of their indeterminate width.
The width of a type is the number of bytes required for its individual value. Int8, for example, has a width of 1. An advanced type hashes its elements in sequence and then merges them, so speed depends on the various field types and the number of fields. The hash algorithm for an interface type is determined by the actual type of the value.
It is best not to use advanced data types as dictionary key types, because they are not only slow to hash and evaluate, but their values are variable.


5. Does reading or writing on a dictionary type with a value of nil succeed


Since dictionaries are reference types, declaring a variable that does not initialize a dictionary type will have a nil value, and we can do nothing on a dictionary that has a nil value except add key-element pairs. When we try to add key-element pairs to a dictionary with a value of nil, the Go language’s runtime system immediately throws a panic.


6. Is it safe to perform concurrent operations on the same map in different Goruntine at the same time


Non-atomic operations need to be locked, and map concurrent reads and writes need to be locked. Map operations are not concurrently safe. You can run the Go run race command to check whether an operation is atomic