小编典典

满足接口的Go结构方法的类型

go

给出以下Go代码示例:

package main

import "fmt"

type greeter interface {
    hello()
    goodbye()
}

type tourGuide struct {
    name string
}

func (t tourGuide) hello() {
    fmt.Println("Hello", t.name)
}

func (t *tourGuide) goodbye() {
    fmt.Println("Goodbye", t.name)
}

func main() {
    var t1 tourGuide = tourGuide{"James"}
    t1.hello()   // Hello James
    t1.goodbye() // Goodbye James (same as (&t1).goodbye())

    var t2 *tourGuide = &tourGuide{"Smith"}
    t2.hello()   // Hello Smith
    t2.goodbye() // Goodbye Smith (same as (*t2).hello())

    // illegal: t1 is not assignable to g1 (why?)
    // var g1 greeter = t1

    var g2 greeter = t2
    g2.hello()   // Hello Smith
    g2.goodbye() // Goodbye Smith
}

我可以tourGuide使用tourGuide类型的变量t1或指向tourGuide的指针来调用结构的两个方法t2。换句话说,我可以T使用类型为T或的变量来使用Receiver
调用方法*T。类似地,我可以调用一个方法*T使用类型的变量接收机T(如果T可寻址的)或*T。我了解编译器会在此处处理这些差异(请参见代码中的注释)。

但是,当我们实现接口时,情况会发生变化。在上面的代码中,类型为greeterinterface
的变量可以从指针分配,tourGuide但不能从指针分配tourGuide

谁能告诉我为什么会这样吗?为什么我可以打电话t1.hello()t1.goodbye()t1对于接口来说却是不足够的greeter


阅读 284

收藏
2020-07-02

共1个答案

小编典典

如果方法具有指针接收器,则只能将指针值用作接收器值。因此,要在某个值上调用此方法,该值本身必须是一个指针,或者必须有可能获取其地址(用作接收方)。

例如,如果您有一个变量,则该变量是可寻址的,因此可以获取其地址并将其用作接收器。规范允许您执行此操作,这会自动发生。

包装在接口中的值是不可寻址的。创建接口值时,将复制包装在接口中的值。因此,无法使用其地址。从理论上讲,您可以允许获取副本的地址,但这将带来(甚至)比提供的好处更多的混乱,因为该地址将指向副本,并且带有指针接收器的方法只能修改副本而不是原始的。

2020-07-02