Почему функция Go Function Field Setter не сохраняет эту функцию?


Учитывая эту короткую программу:

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

Почему бы и нет? Заметьте, что результат будет таким, как и ожидалось, если я установлю foo.doer непосредственно в main(). Только не в том случае, если я использую метод SetDoer.

1 2

1 ответ:

В Go элемент слева от имени функции является типом приема. Это тип, из которого может быть вызвана функция. Однако приемником могут быть как указатели, так и типы значений. В данном случае это ценность. Приемник служит исключительно для целей организации, под прикрытием, он передается функции, как и любой другой аргумент. Вы проходите мимо значения, поэтому копия foo передается в SetDoer, значение изменяется, затем возвращается сеттер, значение выходит за пределы области и в вызывая scope, вы работаете с оригиналом.

Попробуйте это;

// 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.

Пример игровой площадки; https://play.golang.org/p/ZQlvKiluu3