首页 > 解决方案 > 分配给切片的值与指针

问题描述

我正在完成这个“Tour of Go”,我正在这里做这个练习。我最初是这样写的答案:

func Pic(dx, dy int) [][]uint8 {
    outer := make([][]uint8, dy)
    inner := make([]uint8, dx)

    for y, _ := range outer {       
        for x, _ := range inner {
            inner[x] = x^y // this is one of the image functions they give
        }

        outer[y] = inner
    }
    return outer
}

我认为这应该可行,但是当我运行时,Pic(5,5)我得到:

[[0 4 8 12 16] [0 4 8 12 16] [0 4 8 12 16] [0 4 8 12 16] [0 4 8 12 16]]

不对,很明显。

所以,我终于发现我需要将我的inner := make([]uint8, dx)声明移动到第一个循环中,如下所示:

func Pic(dx, dy int) [][]uint8 {
    outer := make([][]uint8, dy)

    for y, _ := range outer {
        inner := make([]uint8, dx)

        for x, _ := range inner {
            inner[x] = x^y // this is one of the image functions they give
        }

        outer[y] = inner
    }
    return outer
}

现在Pic(5,5)给我正确的答案:

[[0 0 0 0 0] [0 1 2 3 4] [0 2 4 6 8] [0 3 6 9 12] [0 4 8 12 16]]

这里发生了什么事?我认为这与指针或其他东西有关,但我想确定我真的了解发生了什么。显然,在第一个示例中,每次我将新的东西重新分配给之前分配给它们inner的值时,它们也会发生变化。outerinner

但是在第二个例子中会发生什么?每次我们通过range outer循环时,inner变量都会被重新声明,但是outer之前inner分配给它们的值会发生什么?它们现在是否以某种方式“被切断”并且仅作为副本存在?

我主要感到困惑,因为分配行在outer[y] = inner这两个示例中都没有改变,所以我不明白其中一个分配值副本的机制,而在另一个分配中分配我认为的内容一个指针。

标签: go

解决方案


在第一种情况下,您从未“将新的东西重新分配给inner”。uint8您创建了一个名为的切片inner,并在其中填充了值(多次覆盖这些值),并使的每个元素都outer包含 的副本inner。但请记住,切片只是存在于某处的数组的视图(在您的情况下,支持数组是由匿名创建的make)。复制切片不会复制数组中的值,它只是复制切片标头,这意味着现在有多个视图在同一个存储上(这很好,也很安全)。

在第二种情况下,您调用make的每一行outer,因此创建了五个不同的支持数组,inner每次都指向不同的数组。这一次,当你分配inner给 的一个元素时outer,你得到了五个真正不同的切片头,而不是同一个的五个副本。

简而言之:切片是一个值,但它是一个包含指针的值。指针可能指向一个有名字的数组,也可能指向一个完全匿名的数组。没有什么可担心的;Go 将确保任何被指向的东西都保持活力。


推荐阅读