Pointers 当go中的form参数是map时,传入了什么?
当形式参数为map时,直接向形式参数赋值不能更改实际参数,但是如果向形式参数添加新的键和值,也可以看到函数外部的实际参数。为什么呢 我不理解下面代码的输出值,形式参数与实际参数不同Pointers 当go中的form参数是map时,传入了什么?,pointers,go,go-map,Pointers,Go,Go Map,当形式参数为map时,直接向形式参数赋值不能更改实际参数,但是如果向形式参数添加新的键和值,也可以看到函数外部的实际参数。为什么呢 我不理解下面代码的输出值,形式参数与实际参数不同 unc main() { t := map[int]int{ 1: 1, } fmt.Println(unsafe.Pointer(&t)) copysss(t) fmt.Println(t) } func copysss(m map[int]int)
unc main() {
t := map[int]int{
1: 1,
}
fmt.Println(unsafe.Pointer(&t))
copysss(t)
fmt.Println(t)
}
func copysss(m map[int]int) {
//pointer := unsafe.Pointer(&m)
//fmt.Println(pointer)
m = map[int]int{
1: 2,
}
}
我想知道参数是值还是指针。在Go中,map是引用类型。这意味着映射实际上驻留在堆中,而变量只是指向该堆的指针 地图是按副本传递的。您可以在函数中更改本地副本,但这不会反映在调用方的作用域中 但是,由于map变量是指向驻留在堆中的唯一映射的指针,因此任何指向同一映射的变量都可以看到每个更改 本文可以阐明以下概念:。参数既是一个值也是一个指针 等待为什么? 是的,映射(以及切片)是类型,与您要实现的非常相似。想象一下这样的地图:
type map struct {
// meta information on the map
meta struct{
keyT type
valueT type
len int
}
value *hashTable // pointer to the underlying data structure
}
func update(s []int) {
for i, v := range s {
s[i] = v*2
}
}
因此,在第一个函数中,重新分配m
,传递上述结构的副本(按值传递),并为其分配一个新映射,在此过程中创建一个新的哈希表指针。函数作用域中的变量会被更新,但是您传递的变量仍然保留对原始映射的引用,并且使用它,指向原始映射的指针会被保留
在第二个代码段中,您正在访问底层哈希表(指针的副本,但指针指向同一内存)。您直接操作原始地图,因为您只是更改内存的内容
So TL;博士
映射是一个值,包含映射外观的元信息,以及指向存储在其中的实际数据的指针。指针是按值传递的,就像其他任何东西一样(与C/C++中指针按值传递的方式相同),但当然,取消对指针的引用意味着直接更改内存中的值
仔细的
正如我所说,切片的工作方式基本相同:
type slice struct {
meta struct {
type T
len, cap int
}
value *array // yes, it's a pointer to an underlying array
}
底层数组是这样的,即如果一个int片段的cap是10,则该片段将是[10]int
,而与长度无关。切片由go运行时管理,因此如果超出容量,将分配一个新数组(是上一个数组的cap
的两倍),复制现有数据,并将切片value
字段设置为指向新数组。这就是为什么append
返回要追加的切片,底层指针可能已更改等。。您可以找到有关这方面的更深入的信息
需要注意的是,函数如下所示:
type map struct {
// meta information on the map
meta struct{
keyT type
valueT type
len int
}
value *hashTable // pointer to the underlying data structure
}
func update(s []int) {
for i, v := range s {
s[i] = v*2
}
}
将以与正在分配的函数m[1]=2
相同的方式运行,但一旦开始追加,运行时就可以随意移动底层数组,并指向新的内存地址。所以底线是:贴图和切片有一个内部指针,它可能会产生副作用,但最好避免bug/歧义。Go支持多个返回值,所以如果您打算更改它,只需返回一个切片即可
笔记:
在您尝试弄清楚什么是映射(引用、值、指针…)时,我注意到您尝试了以下方法:
pointer := unsafe.Pointer(&m)
fmt.Println(pointer)
您在那里所做的,实际上是打印参数变量的地址,而不是任何实际对应于映射本身的地址。传递给的参数不安全。指针
的类型不是map[int]int
,而是*map[int]int
类型
就我个人而言,我认为传递值和传递值之间有太多的混淆。Go在这方面与C完全一样,就像C一样,绝对所有的东西都是通过值传递的。碰巧这个值有时可以是内存地址(指针)
更多详情(参考资料)
-
注:由于指针、切片和映射被称为*引用类型*,因此存在一些混淆,但是正如其他人和其他地方所解释的,这不应该与C++引用混淆。
type slice struct {
meta struct {
type T
len, cap int
}
value *array // yes, it's a pointer to an underlying array
}
func update(s []int) {
for i, v := range s {
s[i] = v*2
}
}
pointer := unsafe.Pointer(&m)
fmt.Println(pointer)