带指针接收器的Golang方法

时间:2015-11-26 10:23:03

标签: go

我有这个示例代码

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?,但我看不出它与这个例子的关系。

2 个答案:

答案 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的指针来完成方法调用。一旦建立了这样的指针,就可以访问(并可能修改)接口变量的动态值而无需复制它。