为什么slice []结构与[] builtin的行为不同?

时间:2015-05-24 09:23:43

标签: go reference

切片是对底层数组的引用。这是有道理的,似乎适用于内置/原始类型,但为什么不在结构上工作?我假设即使我更新结构字段,引用/地址仍然是相同的。

package main

import "fmt"

type My struct {
    Name string
}

func main() {
    x := []int{1}
    update2(x)
    fmt.Println(x[0])
    update(x)
    fmt.Println(x[0])
    my := My{Name: ""}
    update3([]My{my})
    // Why my[0].Name is not "many" ?
    fmt.Println(my)
}

func update(x []int) {
    x[0] = 999
    return
}
func update2(x []int) {
    x[0] = 1000
    return
}
func update3(x []My) {
    x[0].Name = "many"
    return
}

澄清一下:我知道我可以在两种情况下使用指针。我只是为什么没有更新结构(不像int)。

3 个答案:

答案 0 :(得分:2)

调用update3时所执行的操作是传递包含值副本的新数组,然后立即丢弃该数组。这与您使用基元所做的不同,因为您保留了数组。

这里有两种方法。

1)使用指针数组而不是值数组:

您可以像这样定义update3

func update3(x []*My) {
    x[0].Name = "many"
    return
}

并使用

调用它
update3([]*My{&my})

2)写入数组(与处理原语的方式相同)

arr := make([]My,1)
arr[0] = My{Name: ""}
update3(arr)

答案 1 :(得分:0)

来自GO FAQ:

  

与C系列中的所有语言一样,Go中的所有内容都通过   值。也就是说,一个函数总是得到一个东西的副本   传递,好像有一个赋值的赋值语句   到参数。例如,将int值传递给函数   制作int的副本,并传递指针值制作副本   指针,但不指向它指向的数据。 (参见下一节   讨论它如何影响方法接收器。)

     

Map和slice值的行为类似于指针:它们是描述符   包含指向底层地图或切片数据的指针。复制地图或   切片值不会复制它指向的数据。

因此,当您传递my时,您传递的是结构的副本,并且调用代码不会看到对该副本所做的任何更改。

要让函数更改teh结构中的数据,必须将指针传递给结构。

答案 2 :(得分:0)

您的第三次测试与前两次测试不同。看看这个(Playground)。在这种情况下,您不需要使用指针,因为您没有修改切片本身。您正在修改基础数组的元素。如果要修改切片,例如,附加一个新元素,则需要使用指针通过引用传递切片。请注意,我更改了打印件以显示类型和值。