4

面试扣分点:什么是鸭子类型

 2 years ago
source link: https://www.kingname.info/2021/07/03/what-is-duck-type/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

面试扣分点:什么是鸭子类型

发表于

2021-07-03

| 分类于 面试

| 评论数:

有一类面试官特别讨厌,面试的时候,会问一些偏、难、怪的题目。假设你今天去面试,遇到面试官问你:“什么是鸭子类型?”。你怎么回答?

熟读维基百科的你,脑海中闪过了下面这张截图:

2021-07-01-23-07-04.png

图中的红框像闪电一样从你的脑子里划过。你用中指扶了扶黑框眼镜,自信地说道:

鸭子类型就是说,一个函数不会关心它传入参数的类型,只关心这个参数对应的对象有没有自己想要的方法和属性。如果有,就能运行。如果没有,就不能运行。这就像是我看到了一只鸟,只要它能像鸭子一样叫,像鸭子一样走路,有鸭子一样的白色羽毛,那么,无论它实际上是什么东西,我都认为它是鸭子。

说完这段话,一道光从你的镜片上一闪而过。你心里想,这下稳了。

面试官又问:那你用 Golang 写一个鸭子类型的例子。

你一想,Golang 是静态语言啊,参数都要声明类型的,怎么绕过它的类型检测呢?你又转念再一想,不对,Golang 确实可以绕过类型检测的。使用接口就可以了。

于是你刷刷刷写下来一段 Golang 语言的代码:

package main


import (
"fmt"
)


type Animal interface {
Sleep()
Eat(food string)
}


type People struct {
name string
}

type Pet struct {
name string
}

func (p People) Sleep(){
fmt.Println(p.name, "在睡觉")
}

func (p Pet) Sleep() {
fmt.Println(p.name, "在睡觉")
}

func (p People) Eat(food string) {
fmt.Printf("%s在吃%s\n", p.name, food)
}

func (p Pet) Eat(food string) {
fmt.Printf("%s在吃%s\n", p.name, food)
}

func check(animal Animal) {
animal.Eat("狗狼")
animal.Sleep()
}


func main(){
singleDog := People{name: "单身狗",}
dog := Pet{name: "旺财",}
check(singleDog)
check(dog)
}

代码运行效果如下图所示:

2021-07-01-23-38-04.png

然后你解释道,在函数main()里面,变量singleDog的类型是 People 类型,变量dog的类型是Pet类型。虽然他们是不同的类型,但是由于他们都有Eat方法和Sleep方法,所以,他们都能在check函数里面运行。

面试官又问,你的代码写得没有问题,例子也举得没有问题。那我再问你,既然check函数不关心传入参数的类型,只关心他们的方法,是不是说明check函数接收的参数是鸭子类型?

你说,是的。

面试官又问,但是,我们从代码里面可以看到,check函数接收的这个参数animal的类型是接口类型。那是不是说明接口类型等于鸭子类型

你一时回答不上来。

面试官又问:那接口类型和鸭子类型是什么关系?鸭子类型是像intstringmap这样内置的类型吗?我们可以在 Golang 里面使用var a string 声明一个类型为string的变量,那请问怎么声明一个类型为鸭子的变量?

你一时想不起来 Golang 自带的关键词里面,哪个关键词包含duck这个单词。

面试官露出了耐克式的微笑,对你说:“回家等通知吧。”

这个讨厌的面试官最后一个问题把你难住了。但是这个问题其实是一个陷阱。面试官给你玩了一个文字游戏。当他把鸭子类型整型、字符串类型合在一起说的时候,让你觉得鸭子类型也是一种类型。但实际上鸭子类型并不是一种类型,鸭子类型是一种动态类型的风格:

2021-07-01-23-55-07.png

怎么解释什么叫做设计风格呢?我们再用 Python 举个例子:

  • 确保传入的变量必须是特定类型,再执行对应的方法
# 确保参数是特定类型再调用里面的方法
def check(animal):
if isinstance(animal, Pet):
animal.eat()
elif isinstance(animal, People):
animal.eat()
else:
raise Exception("类型错误!")
  • 不管传入的参数是什么类型,只要它有 eat方法都能执行。如果这个对象没有eat方法,Python 自动就会抛出异常。
def check(animal):
animal.eat()

在鸭子类型这种设计风格中,开发者不关心对象是什么类型。它只关心对象有没有特定的方法。

总结:鸭子类型是一种设计风格,不是一种具体的类型。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK