sync.Map 在删除时如果是 read 中的 key ,那么并不是真实的删除,而是将 entry 中的 p 置换成 nil ,但是 value 直接设置为 nil ,那么怎么区分一个值是被置换成了 nil 还是一开始就设置为 nil 呢?
1
Trim21 53 天前
sync.Map.Load 方法有两个返回值
|
2
grzhan 52 天前 5
关键在于 Sync.Map.Store(k, v) ,当你传值为 nil 调用 Store 时,因为 k,v 的类型是 any (也就是 interface{}),在 runtime 也就是结构体 iface ,如果你传入的是 nil ,golang 会用 iface 把这个 nil 包一下,对应的 _type 与 data 应该都是空值(nil),所以你可以在 sync.Map.Store 里面后续的源码里可以看到,value 是可以拿到内存地址的(&value ),因为这个 value 本质上是个 iface 结构体,而直接写 &nil 在 Golang 是会编译报错的。
而 readOnly.m 的值类型是 entry ,entry.p 是一个指向 interface{} 值的指针。当你调用 Sync.Map.Store(k, nil) 时,对应的 entry.p 不会变成 nil ,而是变成一个指向 interface{} (iface) 的指针,这个 iface 相当于包装了值 nil 。 而 Sync.Map.Delete() 就确实会把 entry.p 变成 nil ,所以二者确实是有明确区别的。 写一个函数就可以简单验证,也可以汇编拿出来自己看下: package main import "fmt" func printAnyAddr(v any) { fmt.Println(&v) } func main() { printAnyAddr(nil) } |
3
grzhan 52 天前
这里 iface 写错了,interface{} 应该是对应 eface
|
4
kingcanfish 52 天前 1
func main() {
var a interface{} fmt.Println(a == nil) a = (*int)(nil) fmt.Println(a == nil) } 上面的答案是 true 和 false OP 要是弄懂了上面的原因 ,那应该就能弄懂你提的问题 |
5
rainbowStay OP @grzhan #2 感谢回复,解答得很清晰
|