golang.org/x/sync/syncmap 被 struct 裹挟时 使用前为什么必须为每个键初始化 不然取值得到 nil - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
zhouyin
V2EX    Go 编程语言

golang.org/x/sync/syncmap 被 struct 裹挟时 使用前为什么必须为每个键初始化 不然取值得到 nil

  •  
  •   zhouyin 2 天前 860 次点击
    package main import ( "fmt" syncmap "golang.org/x/sync/syncmap" ) type Mark struct{ Values syncmap.Map } var chanA chan int = make(chan int , 1) func (m Mark)funa(){ go func(){ m.Values.Store("a",1) chanA<-1 }() <-chanA } func main() { var mk = new (Mark) mk.Values.Store("a",0) mk.funa() va, p := mk.Values.Load("a") fmt.Printf("%v:%v\n",va,p) } 

    没有这行 mk.Values.Store("a",0) 永远取不到值 va 等于 nil p 等于 false

    7 条回复    2025-10-22 11:17:56 +08:00
    zhouyin
        1
    zhouyin  
    OP
       2 天前
    需要把函数 funa 定义成指针接收者 就不需要初始化
    ```golang
    func (m *Mark)funa(){

    go func(){
    m.Values.Store("a",1)
    chanA<-1
    }()

    <-chanA
    }
    ```
    道理上想不通 值接收者如果设计到变量拷贝 那么在函数里赋值也没用
    buffzty
        2
    buffzty  
       2 天前
    加个*号
    iseki
        3
    iseki  
       2 天前 via Android
    > A Map must not be copied after first use.
    SGL
        4
    SGL  
       2 天前
    原文档内容:The zero Map is empty and ready for use. A Map must not be copied after first use.

    Map 的定义如下:
    ```
    type Map struct {
    _ noCopy // 这个在源码中设置

    m isync.HashTrieMap[any, any]
    }
    ```

    noCopy 类型的说明:
    noCopy may be added to structs which must not be copied
    after the first use.

    See https://golang.org/issues/8005#issuecomment-190753527
    for details.

    Note that it must not be embedded, due to the Lock and Unlock methods.

    如果你想问,进一步为什么 Map 是“noCopy"的,需要进一步研究 HashTrieMap 的结构:

    ```go
    type HashTrieMap[K comparable, V any] struct {
    inited atomic.Uint32
    initMu Mutex
    root atomic.Pointer[indirect[K, V]]
    keyHash hashFunc
    valEqual equalFunc
    seed uintptr
    }
    ```
    可以看到里面封装了 Mutex ,先不管其他变量,至少 Mutex 是肯定不可拷贝的, 内部维护锁的状态( locked/unlocked )以及等待队列这些资源。
    Ketteiron
        5
    Ketteiron  
       1 天前
    值接收者会强制复制值,这应该知道吧。
    简单来说,sync.Map, sync.Mutex 不能被复制,在你这个用例中,读和写是不同的 map 实例。
    zhouyin
        6
    zhouyin  
    OP
       1 天前
    @SGL
    对 struct 被拷贝导致 iniMutex 被拷贝了 具体业务代码里 多个 go routine 总共有好几次 Store 就只有一次 Store 的 Key 取出来是 nil 其他 Store 的 key 都有值 说明一开始有两个 goroutine 竞争初始化 导致第一个 goroutine 没 Store 完毕 被第二个 goroutine 初始化整个 map 了
    zhouyin
        7
    zhouyin  
    OP
       1 天前
    @Ketteiron
    原因是竞争初始化 Mutex 操作的是同一个 map 因为所有 struct 实例持有的都是 map 的指针地址
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5355 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 37ms UTC 01:32 PVG 09:32 LAX 18:32 JFK 21:32
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86