Go中这两种“切片复制”方法之间有什么区别

时间:2020-06-30 08:09:03

标签: arrays go slice

那么,为什么它们(下面的1号和2号)不同?


type T1 struct {
    local []string
}

func (t *T1) Assign(param ...string) {
    t.local = nil
    t.local = append(t.local, param...) // No.1 <<<
    t.local = param[:]                  // No.2 <<<
}

他们不同,可以肯定的是:第二名非常“浅”。

t.local[i]发生一次更改时,如果使用2号,她将使原始字符串乱码。

2 个答案:

答案 0 :(得分:2)

您的“ No.1”方法将附加到nil切片上,这可以确保如果提供的参数超过零,则将分配新的支持数组。

您的“第二”方法不会创建新的切片,而只是对参数进行切片。

如果通过传递现有切片来调用Assign(),则第二种方法将存储该切片,并且如果修改其元素,它将反映在存储的切片中。

让我们稍微修改一下示例以对其进行测试:

type T1 struct {
    local []string
}

func (t *T1) Assign1(param ...string) {
    t.local = nil
    t.local = append(t.local, param...) // No.1 <<<
}

func (t *T1) Assign2(param ...string) {
    t.local = nil
    t.local = param[:] // No.2 <<<
}

测试:

t1 := &T1{}

s := []string{"a", "b", "c"}
t1.Assign1(s...)
fmt.Println(t1.local)
s[0] = "x"
fmt.Println(t1.local)

s = []string{"a", "b", "c"}
t1.Assign2(s...)
fmt.Println(t1.local)
s[0] = "x"
fmt.Println(t1.local)

输出(在Go Playground上尝试):

[a b c]
[a b c]
[a b c]
[x b c]

如您所见,使用Assing1()时,local片不受修改传递的片的影响。

使用Assing2()时,local切片的元素反映了原始文档中所做的更改。

请阅读相关博客文章:

The Go Blog: Go Slices: usage and internals

The Go Blog: Arrays, slices (and strings): The mechanics of 'append'

答案 1 :(得分:0)

当切片容量不足时,append函数会分配一个新的后备阵列

使用[:]进行拆分,只是实例化了一个新的 slice标头,该标头指向相同的后备数组。

请考虑以下代码段:

func main() {
    a := make([]int, 4, 5)

    fmt.Println("Len", len(a)) // 4
    fmt.Println("Cap", cap(a)) // 5

    fmt.Printf("Array 0th: %p\n", &a[0]) // memory address of the first element of backing array

    a = append(a, 10)

    fmt.Printf("Array 0th: %p\n", &a[0]) // same memory address as before

    b := a[:]

    fmt.Printf("Array 0th: %p\n", &b[0]) // same memory address as before

    a = append(a, 10) // grow over capacity

    fmt.Printf("Array 0th: %p\n", &a[0]) // different memory address

}

您可以在the official Go blog上找到有关切片的更多信息。