为什么 Go 禁止取 (&) 映射成员的地址,却允许取 (&) 切片元素?

2024-05-15

Go 不允许获取地图成员的地址:

// if I do this:
p := &mm["abc"]
// Syntax Error - cannot take the address of mm["abc"]

理由是,如果 Go 允许使用此地址,那么当地图后台存储增长或缩小时,该地址可能会变得无效,从而使用户感到困惑。

但是 Go 切片在超出其容量时会被重新定位,但是 Go 允许我们获取切片元素的地址:

 a := make([]Test, 5)
 a[0] = Test{1, "dsfds"}
 a[1] = Test{2, "sdfd"}
 a[2] = Test{3, "dsf"}

 addr1 := reflect.ValueOf(&a[2]).Pointer()
 fmt.Println("Address of a[2]: ", addr1)

 a = append(a, Test{4, "ssdf"})
 addrx := reflect.ValueOf(&a[2]).Pointer()
 fmt.Println("Address of a[2] After Append:", addrx)

 // Note after append, the first address is invalid
 Address of a[2]:  833358258224
 Address of a[2] After Append: 833358266416

Go为什么要这样设计?获取切片元素的地址有什么特别之处?


切片和映射之间有一个主要区别:切片由支持数组支持,而映射则不然。

如果映射增大或缩小,则指向映射元素的潜在指针可能会变成指向任何地方的悬空指针(未初始化的内存)。这里的问题不是“用户的困惑”,而是它会破坏 Go 的一个主要设计元素:没有悬空指针。

如果切片耗尽容量,则会创建一个更大的新后备数组,并将旧后备数组复制到新数组中;和旧的支持阵列remains existing。因此,从指向旧后备数组的“未增长”切片获得的任何指针仍然是指向有效内存的有效指针。

如果您有一个切片仍然指向旧的后备数组(例如,因为您在将切片增长到超出其容量之前创建了切片的副本),您仍然可以访问旧的后备数组。这与切片元素的指针关系不大,但切片是数组的视图,并且数组在切片增长期间被复制。

请注意,在切片收缩期间不存在“减少切片的支持数组”。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 Go 禁止取 (&) 映射成员的地址,却允许取 (&) 切片元素? 的相关文章

随机推荐