关于鸭子类型
Posted seasen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于鸭子类型相关的知识,希望对你有一定的参考价值。
其实对我来说鸭子类型一直是一个比较模糊的概念,因为平常不去关注,关注的时候一般是在面试或者被面试的时候,今天在看一篇博客的时候又有看到,所以就索性弄清楚
```
首先 与duck typing相对应的是normal typing(对象的类型决定对象的特性)
*既然是相对,可以简单理解为 duck typing 就是对象的特性决定了他是什么,说一个烂大街的句子:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”,不是因为它是鸭子所以走路,游泳和叫像鸭子,而是走路,游泳和叫像鸭子所以被``认为``是鸭子
duck typing中对象的类型不重要,只要对象有类型A的方法和属性,那么它被当做类型A来使用。熟悉c的同学应该明白c就是normal typing,在编译阶段静态检查,函数定义和传参类型需要保持一致,不一致就编译报错。参数类型当然也包含了 ``对象`` 参数,后面我会举个Go的例子。
Python中的鸭子类型:
class Duck: def fly(self): print("Duck flying") class Airplane: def fly(self): print("Airplane flying") class Whale: def swim(self): print("Whale swimming") def runtest(obj): obj.fly() duck = Duck() airplane = Airplane() whale = Whale() 此时: runtest(duck) √ runtest(airplane) √ runtest(whale) ×
前两个有fly方法,所以在下面的runtest中直接就可以调用,runtest不去理会你传进来的到底是谁的对象,只要你有这个方法,那么我就可以去调用运行。
其实就是多态的一种体现,多态是什么?“多态是指不同类的对象对同一消息作出响应,同一个接口,不同的对象会做出不同的反应;同一个行为可以通过多种表现形式展现出来就是多态”
例如上面同样的runtest这个接口,输入了不同的对象,打印了不同的结果。
在go语言中的 接口:
首先我们定义一个规范,也就是说定义一个接口: type Duck interface { Quack() // 鸭子叫 DuckGo() // 鸭子走 } 这个接口是鸭子的行为,我们认为,作为一只鸭子,它需要会叫,会走。然后我们再定义一只鸡: type Chicken struct { } 假设这只鸡特别厉害,它也会像鸭子那样叫,也会像鸭子那样走路,那么我们定义一下这只鸡的行为: func (c Chicken) Quack() { fmt.Println("嘎嘎") } func (c Chicken) DuckGo() { fmt.Println("大摇大摆的走") }。 *注意,这里只是实现了 Duck 接口方法,并没有将鸡类型和鸭子接口显式绑定。这是一种非侵入式的设计。 然后我们让这只鸡,去叫,去像鸭子那样走路: func main() { c := Chicken{} var d Duck d = c d.Quack() d.DuckGo() # 这一点目前有点疑问,关于接口可以先参照下面的题外话代码 } 执行之后我们可以得到结果: 嘎嘎 大摇大摆的走
这里 go 的
func (c Chicken) DuckGo()
func (c Chicken) Quack()
两个函数可以看成是Python中的方法,go利用接口 type Duck interface 实现了go中的多态,如果没有这个interface的存在,可以看出 一个函数的方法,必须要指定入参的类型,例如func (c Chicken) Quack(),指定了这个入参是Chicken类型的,
如果传入其它的,当然就会编译报错
例:
type Vertex struct {
X, Y float64
}
type Vertex2 struct {
X, Y float64
}
func (v *Vertex) test(){
v.X++;
v.Y++;
}
func main(){
v2 := Vertex2{2,3}
v2.test()
}
# awesomeProject
. est.go:77:3: v.test2 undefined (type Vertex2 has no field or method test)
题外话插一嘴,关于go的接口的,这一部分参考go by exampel:
package main import ( "fmt" "math" ) type geometry interface { area() float64 perim() float64 } type rect struct { width, height float64 } type circle struct { radius float64 } func (r rect) area() float64 { return r.width * r.height } func (r rect) perim() float64 { return 2*r.width + 2*r.height } func (c circle) area() float64 { return math.Pi * c.radius * c.radius } func (c circle) perim() float64 { return 2 * math.Pi * c.radius } func measure(g geometry) { # 这里才体现出了接口的作用,入参统一为geometry,所以下面↓ fmt.Println(g) fmt.Println(g.area()) fmt.Println(g.perim()) } func main() { r := rect{width: 3, height: 4} c := circle{radius: 5} measure(r) # 这里这里,r和c不是同一个结构体对象,但是可以同时作为入参使用measure函数,并且满足在measure中的g.area()和g.perim()方法 measure(c) }
```
知识储备有限,很可能会出现错误,欢迎指正,尤其是go语言部分刚刚接触,所以如果有错误请留言??
参考:
https://www.jianshu.com/p/cd06818935a8
https://www.cnblogs.com/hongjijun/p/12670584.html
以上是关于关于鸭子类型的主要内容,如果未能解决你的问题,请参考以下文章