我仍然在和#34;语言摔跤。我的Go进展的阶段,所以原谅我几乎肯定会遗漏一些非常明显的东西。
我定义了两个结构,一个包含另一个结构。我创建了一个外部结构的数组,将它传递给一个函数,该函数在每个内部结构上调用一个方法,修改它们的内容。此更改在函数中可见,但是当将外部结构添加到数组以进行返回时,外部函数无法查看更改。我已经尝试过无处不在的投掷指针 - 有点谢天谢地,因为它看起来很糟糕。
package main
import "github.com/davecgh/go-spew/spew"
type inner struct {
ints []int
}
func (i *inner) grow() {
i.ints = append(i.ints, 0)
}
type outer struct {
inner inner
}
func growOs(os []outer) (out []outer) {
for _, o := range os {
o.inner.grow()
out = append(out, o)
}
spew.Dump("----------during")
spew.Dump(out)
return
}
func main() {
os := []outer{
outer{},
outer{},
}
spew.Dump("----------pre")
spew.Dump(os)
growOs(os)
spew.Dump("----------post")
spew.Dump(os)
}
答案 0 :(得分:1)
循环中的o
是副本,因此您必须:
[]*outer
。例如:
for i := range os {
o := &os[i]
o.inner.grow()
// or just os[i].inner.grow()
}
return os
os = growOs(os)
答案 1 :(得分:1)
你应该改变
func main() {
os := []outer{
outer{},
outer{},
}
spew.Dump("----------pre")
spew.Dump(os)
growOs(os)
spew.Dump("----------post")
spew.Dump(os)
}
到
func main() {
os := []outer{
outer{},
outer{},
}
spew.Dump("----------pre")
spew.Dump(os)
os = growOs(os)
spew.Dump("----------post")
spew.Dump(os)
}
通知: os = growOs(os)
在功能
func growOs(os []outer) (out []outer) {
for _, o := range os {
o.inner.grow()
out = append(out, o)
}
spew.Dump("----------during")
spew.Dump(out)
return
}
您只需返回一个新切片out
,您就不会修改输入切片os
,
因此,在main
函数中,os
未被更改。
答案 2 :(得分:1)
如果函数需要指针参数,它将获得指向对象的指针,从而对对象执行的每个更改都将对对象本身产生影响。如果函数需要一个值参数,它将获得一个对象的副本,因此每个操作都将影响获得的副本而不是该对象。
func recPointer(s *string) {
fmt.Printf("%p\n", s) // The same object
}
func recValue(s string) {
fmt.Printf("%p\n", &s) // A new object
}
func main() {
s := "asdf"
fmt.Printf("%p\n", &s)
recPointer(&s)
recValue(s)
}
Go的返回值可能会被命名。如果是这样,它们将被视为函数顶部定义的变量。
因此,很明显,命名返回值是在函数中定义的,而不是在它上面的名称空间中定义的。因此,当您返回一个命名值时,您可以使用一个新对象(再次)。
func recValue(s []string) (out []string) {
fmt.Printf("%p\n", &s) // A new object
out = append(out, s...)
// Again new object. It is not the `s` from `main`
// and obviously not the `s` var from incoming arguments.
fmt.Printf("%p\n", &out)
return
}
func main() {
s := []string{"asdf"}
fmt.Printf("%p\n", &s)
recValue(s)
}
小心!我将spew.Dump
替换为fmt.Printf
进行演示调试。
// No named return values
// Pointer argument receiver
func growOs(os *[]outer) *[]outer {
for _, o := range *os {
o.inner.grow()
*os = append(*os, o)
}
fmt.Printf("%p: %+v \n", os, os)
return os
}
func main() {
// `os` is a pointer to the object
os := &[]outer{
outer{},
outer{},
}
fmt.Printf("%p: %+v \n", os, os)
growOs(os)
fmt.Printf("%p: %+v \n", os, os)
}