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()
}