怪奇物语

怪奇物语

首页 新随笔 联系 管理

golang 鸭子类型(Duck Typing)


1. 基础示例:接口的隐式实现

代码


package main

import "fmt"

// 定义接口 Duck,要求实现 Quack() 方法
type Duck interface {
    Quack() string // 鸭子必须会“嘎嘎”叫
}

// 实现 Duck 接口的结构体:RealDuck(真实鸭子)
type RealDuck struct{}

func (r RealDuck) Quack() string {
    return "Quack! Quack!" // 真实鸭子的叫声
}

// 实现 Duck 接口的结构体:ToyDuck(玩具鸭子)
type ToyDuck struct{}

func (t ToyDuck) Quack() string {
    return "Squeak! Squeak!" // 玩具鸭子的叫声
}


// 接收 Duck 接口的函数
func MakeDuckQuack(d Duck) {
    fmt.Println(d.Quack()) // 调用接口的 Quack 方法
}

func main() {
    // 实例化不同类型的鸭子
    real := RealDuck{}
    toy := ToyDuck{}

    // 传递给函数时,无需关心具体类型,只要实现接口即可
    MakeDuckQuack(real) // 输出:Quack! Quack!
    MakeDuckQuack(toy)  // 输出:Squeak! Squeak!
}

关键点

  • 接口隐式实现RealDuckToyDuck 没有显式声明实现 Duck 接口,但通过实现 Quack() 方法,隐式满足接口要求。
  • 多态性MakeDuckQuack 函数接受任何实现了 Duck 接口的类型,无需修改代码即可适配新类型。

2. 鸭子类型的核心特性:动态行为匹配

代码

package main

import "fmt"

// 定义接口:Bird,要求实现 Fly() 和 Sing() 方法
type Bird interface {
    Fly() string
    Sing() string
}

// 结构体:Eagle(老鹰)
type Eagle struct{}

func (e Eagle) Fly() string {
    return "Flying high in the sky!"
}

func (e Eagle) Sing() string {
    return "Screech! Screech!" // 老鹰的叫声
}

// 结构体:Parrot(鹦鹉)
type Parrot struct{}

func (p Parrot) Fly() string {
    return "Flapping wings!"
}

func (p Parrot) Sing() string {
    return "Hello! I'm a parrot!" // 鹦鹉模仿人类说话
}

func main() {
    // 将不同鸟类传递给函数
    makeBirdFlyAndSing := func(b Bird) {
        fmt.Println("Fly:", b.Fly())
        fmt.Println("Sing:", b.Sing())
    }

    makeBirdFlyAndSing(Eagle{}) // 输出:Fly... 和 Screech...
    makeBirdFlyAndSing(Parrot{}) // 输出:Fly... 和 Hello...
}

关键点

  • 动态行为匹配:只要类型实现了接口的所有方法,无论类型是 Eagle 还是 Parrot,都可以被 Bird 接口接受。
  • 无需显式关联:类型无需声明“我是 Bird”,只需实现方法即可。

3. 接口嵌套与组合:复杂场景

代码

package main

import "fmt"

// 定义基础接口
type Animal interface {
    Move() string
}

type Pet interface {
    Name() string
}

// 组合接口:定义一个更复杂的接口
type PetAnimal interface {
    Animal   // 继承 Animal 接口
    Pet      // 继承 Pet 接口
    Play()   // 新增 Play 方法
}

// 实现 PetAnimal 接口的结构体:Dog
type Dog struct{}

func (d Dog) Move() string {
    return "Running on four legs"
}

func (d Dog) Name() string {
    return "Buddy"
}

func (d Dog) Play() {
    fmt.Println("Chasing the ball!")
}

func main() {
    buddy := Dog{}

    // 验证接口实现
    var pa PetAnimal = buddy // 隐式实现 PetAnimal 接口
    fmt.Println(pa.Move())   // 输出:Running on four legs
    fmt.Println(pa.Name())   // 输出:Buddy
    pa.Play()                // 输出:Chasing the ball!
}

关键点

  • 接口嵌套PetAnimal 继承了 AnimalPet 接口,并新增 Play() 方法。
  • 组合优于继承:Go 通过接口嵌套实现功能组合,避免传统 OOP 的继承层级问题。

4. 鸭子类型 vs 静态类型检查

代码示例

package main

import "fmt"

type Swimmer interface {
    Swim() string
}

type Fish struct{}

func (f Fish) Swim() string {
    return "Swimming in water!"
}

func main() {
    var s Swimmer = Fish{} // 鱼实现了 Swimmer 接口
    fmt.Println(s.Swim())  // 输出:Swimming in water!

    // 错误示例:类型未实现接口
    // type Bird struct{} // 没有实现 Swim() 方法
    // var b Swimmer = Bird{} // 编译错误:Bird 不实现 Swim()
}

关键点

  • 静态类型检查:Go 在编译时会严格检查类型是否实现接口的所有方法,未实现则报错(如 Bird 的例子)。
  • 鸭子类型的边界:Go 的接口是“静态鸭子类型”,即行为匹配需在编译时确定,而非运行时。
posted on 2025-04-23 08:00  超级无敌美少男战士  阅读(56)  评论(0)    收藏  举报