非Struct类型中的接口继承

时间:2018-01-27 21:11:39

标签: inheritance go interface

我目前正在学习Go中的界面,但我已经遇到了这段代码:

package main

import (
    "fmt"
    "math"
)

// CommonMath is a common interface for math types
type CommonMath interface {
    Abs() float64
}

// Float64 is a custom float64 type
type Float64 float64

// Abs returns the modulus of objects implementing CommonMath
func (f Float64) Abs() float64 {
    if f < 0 {
        return -float64(f)
    }
    return float64(f)
}

// AbsSquared returns the square of objects implementing CommonMath
func AbsSquared(num CommonMath) float64 {
    return num.Abs() * num.Abs()
}

func main() {
    var f Float64
    f = -5

    type newF Float64
    var newFloat newF
    newFloat = 10.5

    fmt.Println(f)
    fmt.Println(f.Abs())
    fmt.Println(AbsSquared(newFloat))
}

事实证明,它不会编译,因为newFloat没有实现接口CommonMath。属于newF类型,这是一个实现接口的自定义Float64类型,我不知道发生了什么。为了使事情变得更奇怪,我将newF和newFloat的声明替换为以下内容,它实现了相同但作为结构:

type newF struct {
    Float64
}
newFloat := newF{10.5}

突然间,代码构建完美。这是否意味着只有结构可以实现父类型的接口,因此不允许将类型newF直接声明为Float64

1 个答案:

答案 0 :(得分:3)

首先,Go中根本没有继承。网上有几篇文章讨论了Go的设计决策,放弃了oop的许多功能,但这确实超出了这个答案。

进入你的案子。很明显Float64实现CommonMath。它具有CommonMath所需的方法集,因此它适合接口。

但是,当您声明另一个类型type newF Float64时,新类型不会复制方法集,只会复制数据结构。这在spec

中指定
  

类型定义创建一个新的,不同的类型,其具有与给定类型相同的基础类型和操作,并将标识符绑定到它。

     

新类型称为已定义类型。它与任何其他类型不同,包括它的创建类型。

     

已定义的类型可能包含与之关联的方法。它不继承绑定到给定类型的任何方法,但是接口类型的方法集或复合类型的元素保持不变:

// A Mutex is a data type with two methods, Lock and Unlock.
type Mutex struct         { /* Mutex fields */ }
func (m *Mutex) Lock()    { /* Lock implementation */ }
func (m *Mutex) Unlock()  { /* Unlock implementation */ }

// NewMutex has the same composition as Mutex but its method set is empty.
type NewMutex Mutex
// The method set of the base type of PtrMutex remains unchanged,
// but the method set of PtrMutex is empty.
type PtrMutex *Mutex

// The method set of *PrintableMutex contains the methods
// Lock and Unlock bound to its embedded field Mutex.
type PrintableMutex struct {
    Mutex
}

// MyBlock is an interface type that has the same method set as Block.
type MyBlock Block

然后来type NewF struct { Float64 }。初看起来,这看起来很像继承,但Go中再没有这样的东西。它被称为嵌入组合。同样,spec

  

使用类型但没有显式字段名称声明的字段称为嵌入字段。必须将嵌入字段指定为类型名称T或指向非接口类型名称* T的指针,并且T本身可能不是指针类型。非限定类型名称充当字段名称。

     

如果x.f是表示该字段或方法f的合法选择器,则会调用struct x中嵌入字段的字段或方法f。

     

提升字段的作用类似于结构的普通字段,除了它们不能用作结构的复合文字中的字段名称。

     

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

     
      
  • 如果S包含嵌入字段T,则S和* S的方法集都包括带有接收方T的提升方法。* S的方法集还包括带接收方* T的提升方法。

    < / LI>   
  • 如果S包含嵌入字段* T,则S和* S的方法集都包括带有接收者T或* T的提升方法。

  •   

所以,这里的诀窍是促销Float64的方法会提升为NewF。同样,它可能在某种程度上看起来像继承,但它是不同的。请注意,提升的方法仍然属于嵌入式,接收器将始终是原始的。以下代码打印4。

package main

import (
    "fmt"
)

type A struct {}

type B struct {A}

func (A) P() int {
    return 4
}

func (B) P() int {
    return 5
}

func (a A) S() {
    fmt.Println(a.P())
}

func main() {
    B{}.S()
}

playground:https://play.golang.org/p/BuBL69LqeY6