2

考虑以下示例。我不完全理解“在后台”发生了什么并寻求解释。Foo当我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]}
}
4

3 回答 3

8

您的方法签名是func (f Foo) AddToEntry(). 方法的工作方式f.AddToEntry()与以下相同:

g := Foo.AddToEntry
g(f)

接收器只是另一个参数。为什么这很重要?当你传递一个结构并在函数中修改它时会发生什么?在 C、Go 和其他按值传递的语言中,参数中给出的结构只是一个副本。因此,您不能修改原件。只返回新结构。

当您定义 时func (f *Foo) AddToEntry(),您将接收器(第一个参数)定义为指针。显然,给定一个指针,您可以修改原始结构。隐藏的是,当您在 Go 中访问结构时,您正在隐式引用。换句话说,与 Go(*ptrFoo).Entry中的相同ptrFoo.Entry

所以这里的问题是,对于那些不习惯去的人来说,语法隐藏了一些正在发生的事情。在 C 中,除非您将指针传递给它,否则您将永远无法编辑结构。在 Go 中也会发生同样的情况。您需要使用指针接收器来修改您正在接收的内容。

于 2012-08-05T19:25:20.357 回答
5

你读过这个 Go 文档吗?

我应该在值或指针上定义方法吗?

方法:指针与值

Go 编程语言规范

于 2012-08-05T19:03:25.363 回答
2

如何确保我没有复制结构?是否有可能的编译时间/运行时间检查,还是我要小心?

这里的简短回答是,您不能对此进行编译时或运行时(1)检查 - 您只需要小心。一旦你对 Go 有点熟悉,这就变得很自然了。

(1)从技术上讲,您的函数可以使用类型 switch 查询类型是否为指针,但如果您记得这样做,您也会记得将参数设为指针。

于 2012-08-05T19:42:12.090 回答