英文:
Golang method with pointer receiver
问题
我有这个示例代码:
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 // <= 有问题的行
}
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
我已经看过这个问题 https://stackoverflow.com/questions/29221854/in-go-golang-how-can-you-cast-an-interface-pointer-into-a-struct-pointer,但我看不出它与这个示例有什么关系。
英文:
I have this example code
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
does not work as expected because its receiver is not of pointer type.
If I change the method to a pointer receiver, what I would expect to work, it looks like this:
func (i *Implementation) SetSomeField(newValue string) { ...
Compiling this leads to the following error:
prog.go:26: cannot use obj (type Implementation) as type IFace in return argument:
Implementation does not implement IFace (GetSomeField method has pointer receiver)
How can I have the struct
implement the interface and the method SetSomeField
change the value of the actual instance without creating a copy?
Here's a hackable snippet:
https://play.golang.org/p/ghW0mk0IuU
I've already seen this question https://stackoverflow.com/questions/29221854/in-go-golang-how-can-you-cast-an-interface-pointer-into-a-struct-pointer, but I cannot see how it is related to this example.
答案1
得分: 82
你指向结构体的指针应该实现接口。这样你就可以修改它的字段。
看看我如何修改你的代码,使其按照你的期望工作:
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())
}
英文:
Your pointer to the struct should implement the Interface. In that way you can modify its fields.
Look at how I modified your code, to make it working as you expect:
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
得分: 40
简单的答案是,你无法使结构体实现你的接口,并且让SetSomeField
按照你的期望工作。
然而,结构体的指针可以实现接口,所以将你的Create
方法改为return &obj
应该可以解决问题。
根本问题在于,你修改后的SetSomeField
方法不再是Implementation
的方法集。虽然类型*Implementation
会继承非指针接收器的方法,但反过来则不成立。
这是因为接口变量的指定方式与此有关:访问接口变量中存储的动态值的唯一方式是复制它。举个例子,想象一下以下情况:
var impl Implementation
var iface IFace = &impl
在这种情况下,调用iface.SetSomeField
可以工作,因为它可以复制指针并将其用作方法调用中的接收器。如果我们直接将结构体存储在接口变量中,我们需要创建一个指向该结构体的指针来完成方法调用。一旦创建了这样的指针,就可以访问(并可能修改)接口变量的动态值,而无需复制它。
英文:
The simple answer is that you won't be able to have the struct implement your interface while having SetSomeField
work the way you want.
However, a pointer to the struct will implement the interface, so changing your Create
method to do return &obj
should get things working.
The underlying problem is that your modified SetSomeField
method is no longer in the method set of Implementation
. While the type *Implementation
will inherit the non-pointer receiver methods, the reverse is not true.
The reason for this is related to the way interface variables are specified: the only way to access the dynamic value stored in an interface variable is to copy it. As an example, imagine the following:
var impl Implementation
var iface IFace = &impl
In this case, a call to iface.SetSomeField
works because it can copy the pointer to use as the receiver in the method call. If we directly stored a struct in the interface variable, we'd need to create a pointer to that struct to complete the method call. Once such a pointer is made, it is possible to access (and potentially modify) the interface variable's dynamic value without copying it.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论