【问题标题】:How can I define an implementation of Go interface method that receives pointer?如何定义接收指针的 Go 接口方法的实现?
【发布时间】:2017-04-25 04:50:44
【问题描述】:

以下程序运行良好。

package main

import (
    "fmt"
)

type Person interface {
    Hello()
}

type Joker struct {
    Name string
}

func (j Joker) Hello() {
    fmt.Println(j.Name, "says, \"Hello!\"")
}

func main() {
    var j Joker = Joker{"Peter"}
    invokeHello(j)
}

func invokeHello(p Person) {
    p.Hello()
}

这是输出。

$ go run foo.go
Peter says, "Hello!"

但是当我更改Hello 方法以接收指针时,我得到了错误。

package main

import (
    "fmt"
)

type Person interface {
    Hello()
}

type Joker struct {
    Name string
}

func (j *Joker) Hello() {
    fmt.Println(j.Name, "says, \"Hello!\"")
}

func main() {
    var j *Joker = &Joker{"Peter"}
    invokeHello(j)
}

func invokeHello(p *Person) {
    p.Hello()
}

这是错误。

$ go run bar.go
# command-line-arguments
./bar.go:21: cannot use j (type *Joker) as type *Person in argument to invokeHello:
    *Person is pointer to interface, not interface
./bar.go:25: p.Hello undefined (type *Person has no field or method Hello)

如何修复第二个程序?

【问题讨论】:

    标签: pointers go interface


    【解决方案1】:
    func invokeHello(p *Person) {
        p.Hello()
    }
    

    p 是类型*Person*Joker 实现接口Person,将invokeHello 还原为:

    func invokeHello(p Person) {
        p.Hello()
    }
    

    这将修复第二个程序。

    我认为你对golang interface type有误导

    接口类型指定了一个称为其接口的方法集。接口类型的变量可以存储任何类型的值,方法集是接口的任何超集。这种类型被称为实现了接口。

    【讨论】:

    • 再补充一点,你几乎不需要一个指向接口类型的指针。它下面已经是一个指针了。
    【解决方案2】:

    修复

    您不能使用指向interface 类型的指针。 这就是问题所在:

    func invokeHello(p *Person) {
        p.Hello()
    }
    

    应该是:

    func invokeHello(p Person) {
        p.Hello()
    }
    

    接口实现

    类型实现接口。如果类型具有适合于接口中声明的方法的方法,则该接口由该类型实现。

    Go 中的接口提供了一种指定对象行为的方法:如果有东西可以做到这一点,那么它就可以在这里使用。

    类型与指向类型的指针

    Type*Type 是不同的类型。例如*Type 可以实现一个接口,但Type 不能实现它。但是*InterfaceType真的没什么用。

    如果您想在需要接口类型的函数中接收指向类型的指针,请使用指针接收器实现接口,就像您在第二个示例中所做的那样。

    Example:

    type Person interface {
        Hello()
    }
    
    type Joker struct {
        Name string
    }
    
    /*
    A Hello method declared with a pointer receiver which means that a pointer to
    the Joker type (*Joker) not Joker type itself implements Person interface.
    */
    func (j *Joker) Hello() {
        fmt.Println(j.Name, "says, \"Hello!\"")
    }
    
    /*
    invokeHello receives ANY type which statisfies Person interface.
    In this case this is pointer to Joker type.
    */
    func invokeHello(p Person) {
        p.Hello()
    }
    
    func main() {
        i := Joker{"Peter"}
        j := &i
        // Note difference between types
        fmt.Printf(
            "Joker type: %s\nPointer to Joker type: %s\n",
            reflect.TypeOf(i), reflect.TypeOf(j))
        invokeHello(j)
    }
    

    否则,如果您想接收某个类型的值,请使用值接收器实现接口,就像您在第一个示例中所做的那样。

    【讨论】:

    • “如果你想在一个需要接口类型的函数中接收指向类型的指针,请使用指针接收器实现接口,就像你在第二个示例中所做的那样。” -- 你能添加一些代码来证明这一点吗?我认为这是我尝试过的,但显然我的第二个示例不起作用。您能否展示一些工作代码,我可以在其中接收指向需要接口类型的函数中的类型的指针?
    • @LoneLearner,是的。密切关注帖子。半小时后更新。
    • @LoneLearner,抱歉耽搁了。这是您的带有 cmets 和类型打印的 sn-p。希望对您有所帮助。
    • @LoneLearner ,invokeHello 接收接口类型但不是指向接口的指针。
    • 我还是一头雾水。您的代码示例似乎与我的第一个示例相同(在我的问题中)。在我的第一个示例中,invokeHello 接收接口类型(不是指针)。
    猜你喜欢
    • 2017-02-10
    • 1970-01-01
    • 2019-11-23
    • 1970-01-01
    • 1970-01-01
    • 2014-02-16
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多