开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情
“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子."
Duck typing,鸭子类型,是动态编程语言的一种对象推断策略,它更关注对象能如何被使用,而不是对象类型本身。
多态:定义时的类型和运行时的类型不一样。比如动物有多种形态:猫、狗、猪
多态性:不同的类对相同的消息作出不一样的反应
鸭子类型的好处就在于能够避免一些类的重写,无需大量复制相同的代码。前提是需要良好的文档支持,不然会让代码变得很混乱。
go语言
在Go语言中通过接口Interface来实现多态,完美支持鸭子类型。
Go语言不要求类型显示地声明实现某个接口,只要实现了相关的方法即可。Go 接口是一组方法的集合,可以理解为抽象的类型。它提供了一种非侵入式的接口。任何类型,只要实现了该接口中方法集,那么就属于这个类型。比如说实现一个鸭子类型:
先定义一个鸭子叫的接口,以及使用这个接口作为参数的函数
type Duck interface {
Quack()
}
func DuckSay(d Duck) {
d.Quack()
}
再来定义两个结构体,实现不同的鸭子叫:
//假设现在有一个可达鸭类型
type PsyDuck struct{}
//可达鸭声明方法-满足鸭子会嘎嘎叫的特性
func (pd PsyDuck) Quack() {
fmt.Println("PsyDuck quack quack")
}
//假设现在有一个唐老鸭类型
type DonaldDuck struct{}
//唐老鸭声明方法-满足鸭子会嘎嘎叫的特性
func (dd DonaldDuck) Quack() {
fmt.Println("DonaldDuck gaga")
}
最后在main函数里声明两种不同的鸭子类型,并且调用Quack函数:
func main() {
//实例化对象
var pd PsyDuck //可达鸭类型
var dd DonaldDuck //唐老鸭类型
//调用方法 1
pd.Quack() // 因为可达鸭实现了所有鸭子的函数,所以可以这么用
dd.Quack() // 因为唐老鸭实现了所有鸭子的函数,所以可以这么用
//调用方法 2
DuckSay(pd) //因为可达鸭实现了所有鸭子的函数,所以可以这么用
DuckSay(dd) //因为唐老鸭实现了所有鸭子的函数,所以可以这么用
}
对用调用方法2来说,在main函数中调用Quack函数时,传入的是不同的鸭子对象。编译器会在调用Quack函数的时候,隐式地将pd和dd转换为Duck类型。
总结
鸭子类型是一种动态语言风格。在这种风格中,一个对象有效的语义,不是由特定的类或者是实现特定的接口决定,而是由它当前的方法和属性的集合决定。