英文:
Why Doesn't a Go Function Field Setter Retain the Function?
问题
给定这个简短的程序:
package main
import "fmt"
type Foo struct {
doer func()
}
func (f Foo) SetDoer(doer func()) {
f.doer = doer
}
func main() {
foo := Foo{func() { fmt.Println("original") }}
foo.doer()
foo.SetDoer(func() { fmt.Println("replacement") })
foo.doer()
}
输出结果是:
original
original
我本来期望的输出是:
original
replacement
为什么会这样?请注意,如果我直接在main()函数中设置foo.doer,输出结果是符合预期的。只是在使用SetDoer方法时不符合预期。
英文:
Given this short program:
package main
import "fmt"
type Foo struct {
doer func()
}
func (f Foo) SetDoer(doer func()) {
f.doer = doer
}
func main() {
foo := Foo{func() { fmt.Println("original") }}
foo.doer()
foo.SetDoer(func() { fmt.Println("replacement") })
foo.doer()
}
The output is:
original
original
I had expected it to be:
original
replacement
Why isn't it? Note that the output is as expected if I set foo.doer directly in main(). Just not if I use the SetDoer method.
答案1
得分: 5
在Go语言中,函数名左侧的项目是接收类型。这是可以调用函数的类型。然而,接收器可以是指针类型或值类型。在这种情况下,它是一个值类型。接收器纯粹是为了组织的目的,在底层,它像任何其他参数一样传递给函数。你通过值传递,所以foo的副本被传递给SetDoer,该值被修改,然后setter返回,该值超出作用域,在调用作用域中你正在使用原始值。
尝试这样做:
// 将接收器设为指针类型
func (f *Foo) SetDoer(doer func()) {
f.doer = doer
}
// 实例化为指针类型
foo := &Foo{func() { fmt.Println("original") }}
foo.SetDoer(func() { fmt.Println("replacement") })
// 现在foo上的doer版本已经更新。
playground示例:https://play.golang.org/p/ZQlvKiluu3
英文:
In Go, the item on the left of the function name is the receiving type. This is the type from which a function can be called. However, receiver can be both pointers or value types. In this case, it is a value. The receiver is purely for the purpose of organization, under the covers, it is passed to the function like any other argument. You're passing by value so a copy of foo is passed into SetDoer, the value is modified, then the setter returns, the value goes out of scope and in the calling scope you're working with the original.
Try this;
// make the receiver a pointer
func (f *Foo) SetDoer(doer func()) {
f.doer = doer
}
// instantiate as pointer
foo := &Foo{func() { fmt.Println("original") }}
foo.SetDoer(func() { fmt.Println("replacement") })
// now the version of doer on foo has been updated.
playground example; https://play.golang.org/p/ZQlvKiluu3
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论