为什么 slice []struct 的行为与 []builtin 不同?
Why a slice []struct doesn't behave same as []builtin?
切片是对底层数组的引用。这是有道理的,似乎适用于 builtin/primitive 类型,但为什么不适用于结构?我假设即使我更新了一个结构字段,reference/address 仍然是一样的。
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)。
调用 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)
来自GO FAQ:
As in all languages in the C family, everything in Go is passed by
value. That is, a function always gets a copy of the thing being
passed, as if there were an assignment statement assigning the value
to the parameter. For instance, passing an int value to a function
makes a copy of the int, and passing a pointer value makes a copy of
the pointer, but not the data it points to. (See the next section for
a discussion of how this affects method receivers.)
Map and slice values behave like pointers: they are descriptors that
contain pointers to the underlying map or slice data. Copying a map or
slice value doesn't copy the data it points to.
因此,当您传递 my
时,您传递的是结构的副本,调用代码不会看到对该副本所做的任何更改。
要让函数更改结构中的数据,您必须传递一个指向该结构的指针。
您的第三次测试与前两次不同。看看这个(Playground)。在这种情况下,您不需要使用指针,因为您没有修改切片本身。您正在修改基础数组的元素。如果你想修改切片,例如,通过附加一个新元素,你需要使用一个指针来通过引用传递切片。请注意,我更改了打印以显示类型和值。
切片是对底层数组的引用。这是有道理的,似乎适用于 builtin/primitive 类型,但为什么不适用于结构?我假设即使我更新了一个结构字段,reference/address 仍然是一样的。
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)。
调用 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)
来自GO FAQ:
As in all languages in the C family, everything in Go is passed by value. That is, a function always gets a copy of the thing being passed, as if there were an assignment statement assigning the value to the parameter. For instance, passing an int value to a function makes a copy of the int, and passing a pointer value makes a copy of the pointer, but not the data it points to. (See the next section for a discussion of how this affects method receivers.)
Map and slice values behave like pointers: they are descriptors that contain pointers to the underlying map or slice data. Copying a map or slice value doesn't copy the data it points to.
因此,当您传递 my
时,您传递的是结构的副本,调用代码不会看到对该副本所做的任何更改。
要让函数更改结构中的数据,您必须传递一个指向该结构的指针。
您的第三次测试与前两次不同。看看这个(Playground)。在这种情况下,您不需要使用指针,因为您没有修改切片本身。您正在修改基础数组的元素。如果你想修改切片,例如,通过附加一个新元素,你需要使用一个指针来通过引用传递切片。请注意,我更改了打印以显示类型和值。