为什么Go语言的函数字段设置器不保留函数?

huangapple go评论79阅读模式
英文:

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

huangapple
  • 本文由 发表于 2015年12月5日 08:43:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/34099860.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定