Метод Голанга с приемником указателя
У меня есть код примера
package main
import (
"fmt"
)
type IFace interface {
SetSomeField(newValue string)
GetSomeField() string
}
type Implementation struct {
someField string
}
func (i Implementation) GetSomeField() string {
return i.someField
}
func (i Implementation) SetSomeField(newValue string) {
i.someField = newValue
}
func Create() IFace {
obj := Implementation{someField: "Hello"}
return obj // <= Offending line
}
func main() {
a := Create()
a.SetSomeField("World")
fmt.Println(a.GetSomeField())
}
SetSomeField
работает не так, как ожидалось, потому что его приемник не имеет тип указателя.
Если я изменю метод на приемник указателя, что бы я ожидал работать, он выглядит так:
func (i *Implementation) SetSomeField(newValue string) { ...
Компиляция приводит к следующей ошибке:
prog.go:26: cannot use obj (type Implementation) as type IFace in return argument:
Implementation does not implement IFace (GetSomeField method has pointer receiver)
Как я могу < <24 > реализовать интерфейс и метод SetSomeField
изменить значение фактического экземпляра без создания копии?
Здесь взломанный фрагмент:
https://play.golang.org/p/ghW0mk0IuU
Я уже видел этот вопрос В go (golang), как вы можете нарисовать указатель на указатель структуры?, но я не вижу, как это происходит связанные с этим примером.
Ответы
Ответ 1
Ваш указатель на структуру должен реализовать интерфейс. Таким образом вы можете изменить свои поля.
Посмотрите, как я изменил ваш код, чтобы он работал так, как вы ожидаете:
package main
import (
"fmt"
)
type IFace interface {
SetSomeField(newValue string)
GetSomeField() string
}
type Implementation struct {
someField string
}
func (i *Implementation) GetSomeField() string {
return i.someField
}
func (i *Implementation) SetSomeField(newValue string) {
i.someField = newValue
}
func Create() *Implementation {
return &Implementation{someField: "Hello"}
}
func main() {
var a IFace
a = Create()
a.SetSomeField("World")
fmt.Println(a.GetSomeField())
}
Ответ 2
Простой ответ заключается в том, что у вас не будет возможности реализовать ваш интерфейс, когда SetSomeField
работает так, как вы хотите.
Однако указатель на структуру реализует интерфейс, поэтому изменение метода Create
для выполнения return &obj
должно заставить все работать.
Основная проблема заключается в том, что ваш модифицированный метод SetSomeField
больше не находится в наборе методов Implementation
. Пока тип *Implementation
наследует методы приемника не указателя, обратное неверно.
Причина этого связана с тем, как указаны интерфейсные переменные: единственный способ получить доступ к динамическому значению, хранящемуся в переменной интерфейса, - это его копирование. В качестве примера представьте себе следующее:
var impl Implementation
var iface IFace = &impl
В этом случае вызов iface.SetSomeField
работает, потому что он может скопировать указатель для использования в качестве приемника в вызове метода. Если мы непосредственно сохранили структуру в переменной интерфейса, нам нужно создать указатель на эту структуру для завершения вызова метода. После создания такого указателя можно (и возможно модифицировать) динамическое значение переменной интерфейса без копирования.