1.对于golang的组合结构体S,调用S的方法f,将从当前结构体出发,按照查找f,第一个找到的f被调用

如:

package main

import "fmt"

// X
type X struct {
    a int
}

func (x X) Print() {
    fmt.Printf("In X, a = %d\n", x.a)
}

func (x X) XPrint() {
    fmt.Printf("call XPrint(). In X, a = %d\n", x.a)
}

// Y
type Y struct {
    X
    b int
}

func (y Y) Print() {
    fmt.Printf("In Y, b = %d\n", y.b)
}


// Z
type Z struct {
    Y
    c int
}

func (z Z) Print() {
    fmt.Printf("In Z, c = %d\n", z.c)
    //显式的完全路径调用内嵌字段的方法
    z.Y.Print()
    z.Y.X.Print()
}

func main() {
    x := X{a: 1}
    y := Y{
        X: x,
        b: 2,
    }
    z := Z{
        Y: y,
        c: 3,
    }
    //从外向内查找,首先找到的是 Z 的 Print() 方法
    z.Print()
    
    //从外向内查找,最后找到的是 x 的 XPrint()方法
    z.XPrint() // ->外层结构体自动获得了内部成员的方法
    z.Y.XPrint()
}
>>>
In Z, c = 3
In Y, b = 2
In X, a = 1
call XPrint(). In X, a = 1
call XPrint(). In X, a = 1
go没有继承只有组合,组合实现了继承的效果
package main
 
import (
    "fmt"
)
 
type Base struct {
    // nothing
}
 
func (b *Base) F1() {
    fmt.Println("Base.F1")
    b.F2()
}

func (b *Base) F2() {
    fmt.Println("Base.F2")
}
 
type Derived struct {
    Base
}
 
func (d *Derived) F2() {
    fmt.Println("Derived.F2")
}
 
func main() {
    d := &Derived{}
    d.F1()   
}
>>>
Base.F1
Base.F2
// 不会打印"Derived.F2"
// Derived结构体自动含有了Base的方法,虽然重写了F2()方法,
// 但因为go没有继承只有组合,不会根据对象的不同来执行不同的F2(),调用的b.F2()仍然是*Base的F2()方法
golang如何实现多态的效果?--使用interface
package main
 
import (
    "fmt"
)

// 首先需要一个接口,起到类似基类的作用
type B interface{
    F1()
    F2()
}

// 表示Base结构体含有一个实现了F1()和F2()的成员
type Base struct {
    B
}

// Base重写了F1,没有重写F2()
// 根据结构体的组合关系,b.F2()到底调用哪个F2,需要从Base结构体出发,从外到内从上到下寻找最近的F2
// 因为Base没有重写F2(), 所以最近的F2就是Base.B.F2()
func (b *Base) F1() {
    fmt.Println("Base.F1")
    b.F2() // will call Base.B.F2()
}

type BaseBase struct {
    Base
}

func (b *BaseBase) F2() {
    fmt.Println("BaseBase.F2")
}
 
type Derived struct {
    BaseBase
}
 
func (d *Derived) F2() {
    fmt.Println("Derived.F2")
}
 
func main() {
    ori_impl_1 := &BaseBase{}
        // 重要!!!
    // ###将ori_impl_1作为最底层的B接口实现,就可以调用ori_impl_1的F2###
    var b B = &BaseBase{Base{B:ori_impl_1}}
    b.F1()
    
    ori_impl_2 := &Derived{}
    // 将ori_impl_2作为最底层的B接口实现
    var d B = &Derived{BaseBase{Base{B:ori_impl_2}}}
    d.F1()  
}
>>>
Base.F1
BaseBase.F2
Base.F1
Derived.F2

核心思想就是,外层实现接口,通过递归嵌套将被实现的接口实例置于内层,从而达到外层定义,内层使用的效果
BaseBase和Derived都是外层结构体,在它们这一层实现了F2()。ori_impl_1以及ori_impl_2都是外层结构体实现的B接口实例,置于内层完成调用

2. 匿名结构体和结构体的递归嵌套

匿名结构体

struct中的字段可以不用给名称,这时称为匿名字段。匿名字段的名称强制和类型相同。例如:

type animal struct {
    name string
    age int
}

type Horse struct{
    int
    animal
    sound string
}

// Horse等价于
type Horse struct{
    int int
    animal animal
    sound string
}

struct递归嵌套

如果struct中嵌套的struct类型是自己的指针类型,可以用来生成链表或二叉树等数据结构

例如,定义一个单链表数据结构

type Node struct {
    Data string
    Next *Node
}