【问题标题】:Array address when copying variables复制变量时的数组地址
【发布时间】:2017-04-07 08:12:15
【问题描述】:

我想探讨一下当我们尝试复制变量时内存是如何分配的。我做了一些测试,这让我很困惑:

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 := ab指向同一个内存位置,后来就无法解释为什么第一个元素的地址不是相同(应该是相同的元素)。

我改了第一行代码:

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

现在它给了我同样的结果。

我想问的问题是:

  1. 在 Golang 中,当我们做变量复制(b := a)时,我们是否也在内存中创建数据副本?不可变类型和可变类型是否相同?

  2. 如果我们也复制可变类型(例如数组),它如何实现修改变量也会影响其他类型(a[0] = 42 会影响b[0])?

  3. []int 类型与我在上一个案例中测试的[number]int 类型有何不同?

【问题讨论】:

标签: arrays pointers go slice


【解决方案1】:

[3]intarray[]intslice

数组表示它的所有元素,当传递它或分配它时,它的所有元素都会被复制。

切片是小型的、类似结构的描述符,指向底层数组的连续部分。传递或分配时,仅复制此标头(包括指针),因此“新”切片将指向相同的后备数组。

回答您的确切问题:

  1. 是的,如果a 是数组,则b := a 复制所有元素,但如果a 是切片,则仅复制标题。只要只有 1 个 goroutine 访问(修改)a,两者都是安全的,如果多个 goroutine 可以修改它,则没有一个是安全的。

  2. 如果一个数组被复制,它将完全独立于“原始”,修改复制对原始没有影响。如果复制切片,则副本将指向存储元素的同一支持数组。如果您通过复制切片修改元素,则修改唯一的元素,因此通过原始切片检查它,您将只检查元素的唯一“实例”(并观察修改后的值)。

  3. 这是第一句:[]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'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-24
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 2014-07-25
    • 2019-08-30
    相关资源
    最近更新 更多