英文:
Array address when copying variables
问题
我想探索一下在尝试复制变量时内存是如何分配的。我进行了一些测试,其中一个测试让我感到困惑:
func testArrayAddress() {
var a [3]int
b := a
fmt.Printf("a的地址:%p,b的地址:%p\n", &(a[0]), &(b[0]))
}
输出结果为:
a的地址:0xc8200126e0,b的地址:0xc820012700
然而,我认为a和b指向同一个数组,所以第一个元素的起始地址应该是相同的。
这让我怀疑当我们执行语句b := a
时发生了什么?最初我以为在初始化变量a
时,它只会为数组分配一个内存块,而b := a
使得b
指向相同的内存位置,但这不能解释为什么第一个元素的地址不同(它们应该是相同的元素)。
我改变了代码的第一行:
func testArrayAddress() {
var a = []int{1, 2, 3}
b := a
fmt.Printf("a的第一个元素的地址:%p,b的地址:%p\n", &(a[0]), &(b[0]))
}
然后输出结果为:
a的第一个元素的地址:0xc8200126e0,b的地址:0xc8200126e0
现在结果相同了。
我想要问的问题是:
-
在Go语言中,当我们进行变量复制(
b := a
)时,我们是否也在内存中创建了数据的副本?对于不可变类型和可变类型来说,情况是否相同? -
如果我们也对可变类型(例如数组)进行复制,它是如何实现修改变量会影响其他变量的(
a[0] = 42
会影响b[0]
)? -
[]int
类型与我在最后一个示例中测试的[number]int
类型有什么不同?
英文:
I want to explore something about how the memory is allocated when we try to copy a variable. I did some tests and this one confuses me:
func testArrayAddress() {
var a [3]int
b := a
fmt.Printf("address of a %p and of b %p \n", &(a[0]), &(b[0]))
}
The output is:
address of a 0xc8200126e0 and of b 0xc820012700
However as I assume a and b and pointing to the same array so the starting address of the first element should be the same?
This made me doubt that what happened when we exec the statement b := a
? Originally I thought it will just allocate one memory block for the array when we init variable a
, and b := a
makes b
pointing to the same memory location, but then it cannot explain why the address of the first element is not the same (which should be same element).
I changed the first line of code:
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]))
}
Then the output is:
address of a's first element 0xc8200126e0 and of b 0xc8200126e0
It gives me the same result now.
The question I want to ask are:
-
In Golang when we do variable copy (
b := a
), are we also creating a copy of data in the memory? And is it the same for both immutable and mutable type? -
If we are copying for mutable type (eg. array) as well, how it manages to achieve modifying variable will also affects others (
a[0] = 42
will affectb[0]
)? -
How is
[]int
type different from[number]int
type which I tested in the last case?
答案1
得分: 5
[3]int
是一个数组,[]int
是一个切片。
数组表示其所有元素,当传递或赋值数组时,所有元素都会被复制。
切片是小型的类似结构体的描述符,指向底层数组的连续部分。当传递或赋值切片时,只有这个头部被复制(包括指针),所以“新”的切片将指向相同的底层数组。
回答你的具体问题:
-
是的,如果
a
是一个数组,b := a
会复制所有元素,但如果a
是一个切片,只会复制头部。只要只有一个 goroutine 访问(修改)a
,这两种情况都是安全的,如果有多个 goroutine 可能修改它,则都不安全。 -
如果复制一个数组,它将与“原始”数组完全独立,修改副本对原始数组没有影响。如果复制一个切片,副本将指向相同的底层数组,其中存储着元素。如果通过副本切片修改一个元素,你修改的是唯一的元素,因此通过原始切片检查时,你只会检查到该元素的唯一“实例”(并观察到修改后的值)。
-
这在第一句中已经说明了:
[]int
是一个切片,[n]int
是一个数组。
请参阅相关问题:
https://stackoverflow.com/questions/38645175/why-have-arrays-in-go/38645895#38645895
https://stackoverflow.com/questions/40514555/golang-passing-arrays-to-the-function-and-modifying-it/40514753#40514753
阅读以下博文以了解有关切片和数组的更多详细信息:
Go Slices: usage and internals
Arrays, slices (and strings): The mechanics of 'append'
英文:
[3]int
is an array, []int
is a slice.
An array means all its elements, when passing it around or assigning it, all its elements are copied.
Slices are small, struct-like descriptors pointing to a contigous section of an underlying array. When passed around or assigned, only this header is copied (including the pointer), and so the "new" slice will point to the same backing array.
To answer your exact questions:
-
Yes,
b := a
copies all elements ifa
is an array, but only the header ifa
is a slice. Both safe as long as only 1 goroutine accesses (modifies)a
, and none is safe if multiple goroutines may modify it. -
If an array is copied, it will be completely independent from the "original", modifying the copy will have no effect on the original. If a slice is copied, the copy will point to the same backing array where the elements are stored. If you modify an element via the copy slice, you modify the one and only element, and so checking it via the original slice you will just check the only "instance" of the element (and observe the modified value).
-
This is in the first sentence:
[]int
is a slice,[n]int
is an array.
See related questions:
https://stackoverflow.com/questions/38645175/why-have-arrays-in-go/38645895#38645895
https://stackoverflow.com/questions/40514555/golang-passing-arrays-to-the-function-and-modifying-it/40514753#40514753
Read the following blog posts for more details on slices and arrays:
Go Slices: usage and internals
Arrays, slices (and strings): The mechanics of 'append'
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论