@@ -210,6 +210,27 @@ v, ok := m[k]
210210
211211## 赋值
212212
213+ ### 编译器如何选择 assign 函数
214+
215+ mapassign 有几个变种,是由编译器决定具体用哪一个函数的。选择依据:
216+
217+ 1 . key 的类型是否是 string
218+ 2 . 如果不是 string,那么根据 key 的类型大小做选择
219+
220+ 流程图:
221+
222+ ``` mermaid
223+ graph TD
224+ A[key is string] --> |yes|B[mapassign_faststr]
225+ A --> |no|C[key size is 32]
226+ C --> |yes|D[mapassign_fast32]
227+ C --> |no|E[key size is 64]
228+ E --> |yes|F[mapassign_fast64]
229+ E --> |no|G[mapassign]
230+ ```
231+
232+ 几个函数长得都差不多,我们看一下 mapassign 的逻辑就行了:
233+
213234``` go
214235// 和 mapaccess 函数差不多,但在没有找到 key 时,会为 key 分配一个新的槽位
215236func mapassign (t *maptype , h *hmap , key unsafe .Pointer ) unsafe .Pointer {
@@ -564,7 +585,9 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
564585 // TODO: reuse overflow buckets instead of using new ones, if there
565586 // is no iterator using the old buckets. (If !oldIterator.)
566587
567- // xy 包含的是移动的目标,x 表示前(low)半部分,y 表示后(high)半部分
588+ // xy 包含的是移动的目标
589+ // x 表示新 bucket 数组的前(low)半部分
590+ // y 表示新 bucket 数组的后(high)半部分
568591 var xy [2 ]evacDst
569592 x := &xy[0 ]
570593 x.b = (*bmap)(add (h.buckets , oldbucket*uintptr (t.bucketsize )))
@@ -598,8 +621,8 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
598621 }
599622 var useY uint8
600623 if !h.sameSizeGrow () {
601- // Compute hash to make our evacuation decision (whether we need
602- // to send this key/value to bucket x or bucket y).
624+ // 计算哈希,以判断我们的数据要转移到哪一部分的 bucket
625+ // 可能是 x 部分,也可能是 y 部分
603626 hash := t.key .alg .hash (k2, uintptr (h.hash0 ))
604627 if h.flags &iterator != 0 && !t.reflexivekey && !t.key .alg .equal (k2, k2) {
605628 // If key != key (NaNs), then the hash could be (and probably
@@ -627,7 +650,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
627650 }
628651
629652 b.tophash [i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY
630- dst := &xy[useY] // evacuation destination
653+ dst := &xy[useY] // 移动目标
631654
632655 if dst.i == bucketCnt {
633656 dst.b = h.newoverflow (t, dst.b )
@@ -637,9 +660,9 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
637660 }
638661 dst.b .tophash [dst.i &(bucketCnt-1 )] = top // mask dst.i as an optimization, to avoid a bounds check
639662 if t.indirectkey {
640- *(*unsafe.Pointer )(dst.k ) = k2 // copy pointer
663+ *(*unsafe.Pointer )(dst.k ) = k2 // 拷贝指针
641664 } else {
642- typedmemmove (t.key , dst.k , k) // copy value
665+ typedmemmove (t.key , dst.k , k) // 拷贝值
643666 }
644667 if t.indirectvalue {
645668 *(*unsafe.Pointer )(dst.v ) = *(*unsafe.Pointer )(v)
@@ -698,24 +721,7 @@ func advanceEvacuationMark(h *hmap, t *maptype, newbit uintptr) {
698721}
699722```
700723
701- ## 编译期判断
702-
703- ### 编译器如何选择 assign 函数
704-
705- 就两个依据:
706-
707- 1 . key 的类型是否是 string
708- 2 . 如果不是 string,那么根据 key 的类型大小做选择
709-
710- ``` mermaid
711- ```
712-
713- mapassign
714- mapassign_fast32
715- mapassign_fasat64
716- mapassign_faststr
717-
718- ### indirectkey 和 indirectvalue
724+ ## indirectkey 和 indirectvalue
719725
720726key > 128 字节时,indirectkey = true
721727
0 commit comments