为什么要禁止(&)地图成员的地址,但允许(&)切片元素? [英] Why does go forbid taking the address of (&) map member, yet allows (&) slice element?

查看:141
本文介绍了为什么要禁止(&)地图成员的地址,但允许(&)切片元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Go不允许接收地图成员的地址:

  //如果我这样做:
p:=& mm [abc]
//语法错误 - 不能取mm [abc]的地址

基本原理是,如果Go允许使用此地址,当地图的后台存储增长或闪烁时,地址可能会变得无效,导致用户混淆。


$ b $但是,Go允许我们获取切片元素的地址:

 <$ c 
a [1] = Test {2,sdfd}
a [2] = Test {3,dsf}

addr1:= reflect.ValueOf(& a [2])。指针()
fmt.Println( [2]:,addr1)

a = append(a,Test {4,ssdf})
addrx:= reflect.ValueOf(& a [2])。 ()
fmt.Println(追加后的[2]地址:,addrx)

//追加后注意,第一个地址无效
地址[2]:833358258224
地址[2]追加后:833358266416

为什么Go是这样设计的?什么是切片元素的地址特殊?

解决方案

切片和贴图之间有一个主要区别:切片由一个支持数组和映射不是。



如果地图增长或缩小指向地图元素的潜在指针可能会成为指向无处的悬挂指针(未初始化的内存)。这里的问题不是用户混淆,而是它打破了Go的一个主要设计元素:没有悬挂指针。



如果切片用完容量a创建新的更大的后备数组,并将旧的后备数组复制到新的数组中;并且旧的后备数组仍然存在。因此,从指向旧支持数组的未生成片段中获得的任何指针仍然是有效指向有效内存的指针。



如果您仍有一片仍指向旧支持数组(例如,因为您在切片超出容量之前制作了切片的副本),您仍然访问旧的后备数组。这与片段元素的指针有关,但片段是数组中的视图,而数组是在片段增长过程中被复制的。注意,没有减少后备在切片收缩期间,切片阵列。

Go doesn't allow taking the address of a map member:

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

The rationale is that if Go allows taking this address, when the map backstore grows or shinks, the address can become invalid, confusing the user.

But Go slice gets relocated when it outgrows its capacity, yet, Go allows us to take the address of a slice element:

 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

Why is Go designed like this? What is special about taking address of slice element?

解决方案

There is a major difference between slices and maps: Slices are backed by a backing array and maps are not.

If a map grows or shrinks a potential pointer to a map element may become a dangling pointer pointing into nowhere (uninitialised memory). The problem here is not "confusion of the user" but that it would break a major design element of Go: No dangling pointers.

If a slice runs out of capacity a new, larger backing array is created and the old backing array is copied into the new; and the old backing array remains existing. Thus any pointers obtained from the "ungrown" slice pointing into the old backing array are still valid pointers to valid memory.

If you have a slice still pointing to the old backing array (e.g. because you made a copy of the slice before growing the slice beyond its capacity) you still access the old backing array. This has less to do with pointers of slice elements, but slices being views into arrays and the arrays being copied during slice growth.

Note that there is no "reducing the backing array of a slice" during slice shrinkage.

这篇关于为什么要禁止(&amp;)地图成员的地址,但允许(&amp;)切片元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆