golang map is implemented in hashmap.
a hashmap is combined with a hash table array and each array node is a linked list.
unlike C++, golang is using a fixed size of array to replace linked list, and if there
are conflicts of new key-value pairs, golang will put the key-value pairs into a
‘extra’ bucket.
the bucket is defined,
1 | // A bucket for a Go map. |
the map is defined as ‘hmap’,
1 | // A header for a Go map. |
when to access the element,(remove unrelated code)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer
//hash function to calculate the index of the bucket,
hash := alg.hash(key, uintptr(h.hash0))
m := bucketMask(h.B)
bucketloop:
//find the element from current bucket,
for ; b != nil; b = b.overflow(t) {
for i := uintptr(0); i < bucketCnt; i++ {
if b.tophash[i] != top {
if b.tophash[i] == emptyRest {
break bucketloop
}
continue
}
k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
if t.indirectkey() {
k = *((*unsafe.Pointer)(k))
}
if alg.equal(key, k) {
v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
if t.indirectvalue() {
v = *((*unsafe.Pointer)(v))
}
return v
}
}
}
from the source code, we can understand why map is not safe.
And new version of golang has added new sync map.
https://golang.org/pkg/sync/#Map
Additonally,
map is passed by the address,1
func makemap(t *maptype, hint int, h *hmap) *hmap
1 | func f1(m map[string]string) { |
above code will change the value of map element, this is different with slice.