我想探讨一下当我们尝试复制变量时如何分配内存。我做了一些测试,这个让我困惑:
func testArrayAddress() {
var a [3]int
b := a
fmt.Printf("address of a %p and of b %p \n", &(a[0]), &(b[0]))
}
输出结果为:
address of a 0xc8200126e0 and of b 0xc820012700
然而,我假设a和b并指向同一个数组,所以第一个元素的起始地址应该相同?
这让我怀疑当我们执行陈述b := a
时发生了什么?最初我以为它会在我们初始化变量a
时为数组分配一个内存块,而b := a
使b
指向同一个内存位置,但是它无法解释为什么地址第一个元素的不一样(应该是相同的元素)。
我更改了第一行代码:
func testArrayAddress() {
var a = []int{1, 2, 3}
b := a
fmt.Printf("address of a's first element %p and of b %p \n", &(a[0]), &(b[0]))
}
然后输出是:
address of a's first element 0xc8200126e0 and of b 0xc8200126e0
现在它给了我相同的结果。
我想问的问题是:
在Golang中进行变量复制(b := a
)时,我们是否还在内存中创建数据副本?对于不可变类型和可变类型都是一样的吗?
如果我们也在复制可变类型(例如数组),它如何设法实现修改变量也会影响其他人(a[0] = 42
会影响b[0]
)?
[]int
的类型与我在上一个案例中测试过的[number]int
类型有什么不同?
答案 0 :(得分:5)
数组表示其所有元素,在传递或分配时,所有元素都将被复制。
切片是一种类似于结构的小描述符,指向底层数组的一个连续部分。传递或分配时,只复制此标头(包括指针),因此“新”切片将指向相同的后备阵列。
回答您的确切问题:
是的,如果b := a
是一个数组,则a
会复制所有元素,但如果a
是一个切片,则只复制标题。只要只有1个goroutine访问(修改)a
,两者都是安全的,如果多个goroutine可以修改它们,则没有一个是安全的。
如果复制了一个数组,它将完全独立于“原始”,修改副本将对原始数据没有影响。如果复制了切片,则副本将指向存储元素的相同后备阵列。如果通过复制切片修改元素,则修改唯一元素,因此通过原始切片检查它,您只需检查元素的唯一“实例”(并观察修改后的值)。
这是第一句话:[]int
是一个切片,[n]int
是一个数组。
查看相关问题:
Why have arrays in Go?
Golang passing arrays to the function and modifying it
阅读以下博客文章,了解有关切片和数组的更多详细信息:
Go Slices: usage and internals
Arrays, slices (and strings): The mechanics of 'append'