【问题标题】:Interface fulfilled by struct embedding结构嵌入实现的接口
【发布时间】:2016-06-07 17:05:54
【问题描述】:

我对以下程序的实验感到困惑,这些程序分别与使用结构嵌入、命名类型和指针接收器实现接口有关:

package main

import "fmt"

type MyInt interface {
    mytest()
}

type Base struct {
}

func (b *Base) mytest() {
    fmt.Println("From base")
}

type Derived struct {
    Base
}

type Derived2 struct {
    *Base
}

func main() {
    // Only this one has problem
    // However, if we change mytest's receiver from *Base to Base, all the four assignments are OK
    var _ MyInt = Derived{}

    // OK
    var _ MyInt = &Derived{}
    var _ MyInt = Derived2{}
    var _ MyInt = &Derived2{}
}

请参阅代码中的 cmets 了解我的困惑。有什么主要的解释方法吗?

【问题讨论】:

    标签: go


    【解决方案1】:

    来自Go language specification

    给定一个结构类型 S 和一个名为 T 的类型,提升的方法是 包含在struct的方法集中如下:

    • 如果 S 包含匿名字段 T,则 S 和 *S 的方法集都 包括带有接收器 T 的提升方法。
    • *S 的方法集也 包括带有接收器 *T 的提升方法。
    • 如果 S 包含匿名 字段 *T,S 和 *S 的方法集都包含提升的方法 与接收器 T 或 *T。

    在您的代码中不起作用的情况:

    var _ MyInt = Derived{}
    

    这里Derived的方法集(包含一个匿名字段Base)包括Base的方法,规则1。由于mytest*Base而不是Base的方法,所以它被提升了到*Derived 的方法(根据第二条规则),但不是Derived 的方法。

    为什么会这样?嗯,它类似于结构体方法集的规则:T 的方法也是T* 的方法,但反之则不然。这是因为指针接收器的方法可以期望能够改变它的接收器,但非指针接收器的方法不能。

    【讨论】:

    • 这解释了它,但我不明白这些规则背后的动机。
    • @M.Tong 我添加了一段解释我认为的动机是什么。
    【解决方案2】:

    根据您的代码函数 mytest 可以在指向 Base 的接收器上调用。

    Struct Derived 继承/嵌入 Base,Derived2 继承/嵌入 *Base,即指向基址的指针。

    对于

    1. var _MyInt = &Derived2{}:这里创建了 Derived2 的指针,并且由于 Derived2 继承自 *Base,因此在 _MyInt 上调用 mytest 将起作用

    2. var _MyInt = Derived2{}:创建了 Derived2 的实例,并且由于 Dervied2 继承自 *Base,因此在 _MyInt 上调用 mytest 将起作用

    3. var _MyInt = &Derived{}:这里创建了 Derived 的指针,并且由于 Derived 继承自 Base,因此在 _MyInt 上调用 mytest 将起作用

    4. var _MyInt = Derived{}:创建了 Derived 的实例,并且由于 Dervied 从 Base 继承,因此在 _MyInt 上调用 mytest 将不起作用,需要指向 Base 的指针。

    您正确地指出,将接收器从 *Base 更改为 Base 将起作用,因为 Go 将能够从指针识别 Object 并能够调用 mytest。

    根据 golang 规范 一个类型可能有一个与之关联的方法集。接口类型的方法集就是它的接口。任何其他类型 T 的方法集由所有以接收者类型 T 声明的方法组成。对应指针类型 *T 的方法集是所有以接收者 *T 或 T 声明的方法的集合(即它还包含该方法T 组)。

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-02
      • 1970-01-01
      • 1970-01-01
      • 2021-01-06
      相关资源
      最近更新 更多