目录

6.3 go 的多态

优质
小牛编辑
116浏览
2023-12-01

Go的多态

go 是一种强类型的语言,每当我从java切换到go时总有些许的不适应,但是追求优雅,就不应该妥协。

go没有 implements, extends 关键字,所以习惯于 OOP 编程,或许一开始会有点无所适从的感觉。 但go作为一种优雅的语言, 给我们提供了另一种解决方案, 那就是鸭子类型:看起来像鸭子, 那么它就是鸭子.

go中的多态比java的隐匿得多,严格上说没有多态,但可以利用接口进行,对于都实现了同一接口的两种对象,可以进行类似地向上转型,并且在此时可以对方法进行多态路由分发,完全代码如下

package main

import (
    "fmt"
)

// Vehicle 是一个超级接口。是所有交通工具必须实现的接口
// 实现这个接口需要实现两个方法,description(),medium()
type Vehicle interface {
    description() string
    medium() string
}

// car 类型.
type Car struct {
    doors int
}

// Boat 类型.
type Boat struct {
    rudders int
    masts   int
}

//description ... Car 实现 Vehicle接口的description方法
// Vehicle interface.
func (c Car) description() string {
    return fmt.Sprintf("I am a car with %v door(s). I move on the %v.", c.doors, c.medium())
}

// medium... Car 实现 Vehicle接口的medium方法
func (c Car) medium() string {
    return "road"
}

// description ... Boat 实现 Vehicle接口的description方法
func (b Boat) description() string {
    return fmt.Sprintf("I am a boat with %v rudder(s) and %v mast(s). I ride on %v.", b.rudders, b.masts, b.medium())
}

// medium... Boat 实现 Vehicle接口的medium方法
func (b Boat) medium() string {
    return "water"
}

// ride  ... 注意接口既能是一个只类型,也可以是一个引用类型。
// 我们使用值类型(`Vehicle`)而不使用引用类型(`*Vehicle`)。
// 参看 @See http://openmymind.net/Things-I-Wish-Someone-Had-Told-Me-About-Go/
func ride(vehicle Vehicle) {
    fmt.Println(fmt.Sprintf("Literal Vehicle: Value is %v. Type is %T.", vehicle, vehicle))
    fmt.Println(vehicle.description())
    fmt.Println(fmt.Sprintf("Did you notice that the vehicle rides on %v?", vehicle.medium()))
}

// checkType ... 类型检查
func checkType(vehicle Vehicle) {
    test1, ok1 := vehicle.(*Car)

    fmt.Println(fmt.Sprintf("Is %v a *Car? %v.", test1, ok1))

    test2, ok2 := vehicle.(Car)

    fmt.Println(fmt.Sprintf("Is %v a Car? %v.", test2, ok2))

    test3, ok1 := vehicle.(*Boat)

    fmt.Println(fmt.Sprintf("Is %v a *Boat? %v.", test3, ok1))

    test4, ok2 := vehicle.(Boat)

    fmt.Println(fmt.Sprintf("Is %v a Boat? %v.", test4, ok2))

    test5, ok3 := vehicle.(Vehicle)

    fmt.Println(fmt.Sprintf("Is %v a Vehicle? %v.", test5, ok3))
}

// main ...
func main() {
    // Using & returns a pointer to the struct value.
    car := &Car{
        doors: 4,
    }

    // Not using & returns the struct value.
    boat := Boat{
        rudders: 1,
        masts:   3,
    }

    fmt.Println("Ride in the car!")
    ride(car)
    fmt.Println()

    fmt.Println("Ride in the boat!")
    ride(boat)
    fmt.Println()

    fmt.Println("Check the type of the car.")
    checkType(car)
    fmt.Println()

    fmt.Println("Check the type of the boat.")
    checkType(boat)
    fmt.Println()
}