我有这个示例代码
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)
如何让struct
实现界面和方法SetSomeField
更改实际实例的值而不创建副本?
这是一个可以破解的片段: https://play.golang.org/p/ghW0mk0IuU
我已经看过这个问题In go (golang), how can you cast an interface pointer into a struct pointer?,但我看不出它与这个例子的关系。
答案 0 :(得分:42)
指向结构的指针应该实现接口。通过这种方式,您可以修改其字段。
看看我如何修改代码,使其按预期运行:
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())
}
答案 1 :(得分:16)
简单的答案是,在SetSomeField
以您想要的方式工作时,您将无法让结构实现您的界面。
但是,指向struct的指针将实现该接口,因此将Create
方法更改为return &obj
可以使事情正常工作。
潜在的问题是,您修改的SetSomeField
方法不再位于Implementation
的方法集中。虽然类型*Implementation
将继承非指针接收器方法,但反之则不然。
其原因与指定接口变量的方式有关:访问存储在接口变量中的动态值的唯一方法是复制它。举个例子,想象一下:
var impl Implementation
var iface IFace = &impl
在这种情况下,对iface.SetSomeField
的调用有效,因为它可以复制指针以用作方法调用中的接收器。如果我们直接在接口变量中存储了一个struct,我们需要创建一个指向该struct的指针来完成方法调用。一旦建立了这样的指针,就可以访问(并可能修改)接口变量的动态值而无需复制它。