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

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

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


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


1.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)
}


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


2.png


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


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


你说,是的。


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


你一时回答不上来。


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


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


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


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


3.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()


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


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


请关注微信公众号【未闻Code】获取更多精彩文章。




目录
相关文章
|
8月前
|
存储 安全 Java
大厂面试题详解:java中有哪些类型的锁
字节跳动大厂面试题详解:java中有哪些类型的锁
321 0
【面试题精讲】Java超过long类型的数据如何表示
【面试题精讲】Java超过long类型的数据如何表示
|
Java 容器
【面试题精讲】Java什么是方法的返回值?方法有哪几种类型?
【面试题精讲】Java什么是方法的返回值?方法有哪几种类型?
|
5月前
|
负载均衡 NoSQL 算法
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
这篇文章是关于Java面试中Redis相关问题的笔记,包括Redis事务实现、集群方案、主从复制原理、CAP和BASE理论以及负载均衡算法和类型。
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
|
5月前
|
Java
【Java基础面试五】、 int类型的数据范围是多少?
这篇文章回答了Java中`int`类型数据的范围是-2^31到2^31-1,并提供了其他基本数据类型的内存占用和数值范围信息。
【Java基础面试五】、 int类型的数据范围是多少?
|
5月前
|
缓存 NoSQL Redis
一天五道Java面试题----第九天(简述MySQL中索引类型对数据库的性能的影响--------->缓存雪崩、缓存穿透、缓存击穿)
这篇文章是关于Java面试中可能会遇到的五个问题,包括MySQL索引类型及其对数据库性能的影响、Redis的RDB和AOF持久化机制、Redis的过期键删除策略、Redis的单线程模型为何高效,以及缓存雪崩、缓存穿透和缓存击穿的概念及其解决方案。
|
6月前
|
SQL 安全 Java
Android经典面试题之Kotlin中object关键字实现的是什么类型的单例模式?原理是什么?怎么实现双重检验锁单例模式?
Kotlin 单例模式概览 在 Kotlin 中,`object` 关键字轻松实现单例,提供线程安全的“饿汉式”单例。例如: 要延迟初始化,可使用 `companion object` 和 `lazy` 委托: 对于参数化的线程安全单例,结合 `@Volatile` 和 `synchronized`
73 6
|
6月前
|
Android开发 Kotlin
Android面试题之kotlin中怎么限制一个函数参数的取值范围和取值类型等
在Kotlin中,限制函数参数可通过类型系统、泛型、条件检查、数据类、密封类和注解实现。例如,使用枚举限制参数为特定值,泛型约束确保参数为Number子类,条件检查如`require`确保参数在特定范围内,数据类封装可添加验证,密封类限制为一组预定义值,注解结合第三方库如Bean Validation进行校验。
98 6
|
6月前
|
监控 Java 调度
Java面试题:描述Java线程池的概念、用途及常见的线程池类型。介绍一下Java中的线程池有哪些优缺点
Java面试题:描述Java线程池的概念、用途及常见的线程池类型。介绍一下Java中的线程池有哪些优缺点
98 1
|
8月前
|
Python
2024年最新【Python】常见的 数据类型:整数类型,Python面试题整理最新
2024年最新【Python】常见的 数据类型:整数类型,Python面试题整理最新
2024年最新【Python】常见的 数据类型:整数类型,Python面试题整理最新

热门文章

最新文章