请考虑以下示例.我不完全理解"在后台"会发生什么并寻求解释.Foo
当我AddToEntry
从main函数调用时,这个版本似乎制作了struct的副本.对?我如何在代码中"证明"这一点?
当go制作结构的副本时,我只是操纵结构的副本,当我回到main
函数时,我会像以前一样看到原始文件?
当我期待一个指针(见代码中的注释),一切都很好,我的结构不会被复制.怎么能避免这种"错误"?我怎样才能确保我没有复制结构?是否有可能的编译时/运行时检查,或者我是否小心?
package main
import (
"fmt"
)
type Foo struct {
Entry []string
}
func MakeFoo() Foo {
a:=Foo{}
a.Entry = append(a.Entry,"first")
return a
}
// if I change (f Foo) to (f *Foo), I get
// the "desired" result
func (f Foo) AddToEntry() {
f.Entry = append(f.Entry,"second")
}
func main() {
f:=MakeFoo()
fmt.Println(f) // {[first]}
f.AddToEntry()
fmt.Println(f) // {[first]}
}
Run Code Online (Sandbox Code Playgroud)
你的方法签名是func (f Foo) AddToEntry()
.方法的工作方式f.AddToEntry()
与以下相同:
g := Foo.AddToEntry
g(f)
Run Code Online (Sandbox Code Playgroud)
接收器只是另一个参数.为什么这很重要?传递结构并在函数中修改它会发生什么?在C,Go和其他值传递语言中,参数中给出的结构只是一个副本.因此,您无法修改原始内容.只返回新结构.
定义时func (f *Foo) AddToEntry()
,您将接收器(第一个参数)定义为指针.显然,给定一个指针,您可以修改原始结构.隐藏的是您在Go中访问结构时隐式引用.换句话说,(*ptrFoo).Entry
就像ptrFoo.Entry
在Go中一样.
所以这里的问题是,对于那些不习惯的人来说,语法隐藏了一些正在发生的事情.在C中,除非传递指向它的指针,否则永远不能编辑结构.Go中也是如此.您需要使用指针接收器来修改您接收的内容.