考虑以下示例。我不完全理解“在后台”会发生什么并寻求解释。当我从main函数调用Foo
时,这个版本似乎会复制struct AddToEntry
。对?我怎样才能在代码中“证明”这个?
当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]}
}
答案 0 :(得分:8)
您的方法签名为func (f Foo) AddToEntry()
。方法的工作方式f.AddToEntry()
与:
g := Foo.AddToEntry
g(f)
接收器只是另一个参数。为什么这很重要?传递结构并在函数中修改它会发生什么?在C,Go和其他值传递语言中,参数中给出的结构只是一个副本。因此,您无法修改原始内容。只返回新结构。
定义func (f *Foo) AddToEntry()
时,您将接收器(第一个参数)定义为指针。显然,给定一个指针,您可以修改原始结构。隐藏的是您在Go中访问结构时隐式引用。换句话说,(*ptrFoo).Entry
与Go中的ptrFoo.Entry
相同。
所以这里的问题是,对于那些不习惯的人来说,语法隐藏了一些正在发生的事情。在C中,除非传递指向它的指针,否则永远不能编辑结构。 Go中也是如此。您需要使用指针接收器来修改您接收的内容。
答案 1 :(得分:5)
您是否阅读过Go文档?
答案 2 :(得分:2)
如何确保我不复制结构?有可能吗? 编译时间/运行时检查,或者我是否小心?
这里简短的回答是没有,你不能做编译时或运行时(1)检查 为此 - 你必须要小心。一旦你对go有点熟悉,这就变得很自然了。
(1) 从技术上讲,你的函数可以使用type switch查询类型是否为指针,但如果你记得这样做,你也会记得将参数作为指针。 < / p>