面試扣分點:什么是鴨子類型
有一類面試官特別討厭,面試的時候,會問一些偏、難、怪的題目。假設你今天去面試,遇到面試官問你:“什么是鴨子類型?”。你怎么回答?
熟讀維基百科的你,腦海中閃過了下面這張截圖:
圖中的紅框像閃電一樣從你的腦子里劃過。你用中指扶了扶黑框眼鏡,自信地說道:
鴨子類型就是說,一個函數不會關心它傳入參數的類型,只關心這個參數對應的對象有沒有自己想要的方法和屬性。如果有,就能運行。如果沒有,就不能運行。這就像是我看到了一只鳥,只要它能像鴨子一樣叫,像鴨子一樣走路,有鴨子一樣的白色羽毛,那么,無論它實際上是什么東西,我都認為它是鴨子。
說完這段話,一道光從你的鏡片上一閃而過。你心里想,這下穩了。
面試官又問:那你用 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)
- }
代碼運行效果如下圖所示:
然后你解釋道,在函數main()里面,變量singleDog的類型是 People 類型,變量dog的類型是Pet類型。雖然他們是不同的類型,但是由于他們都有Eat方法和Sleep方法,所以,他們都能在check函數里面運行。
面試官又問,你的代碼寫得沒有問題,例子也舉得沒有問題。那我再問你,既然check函數不關心傳入參數的類型,只關心他們的方法,是不是說明check函數接收的參數是鴨子類型?
你說,是的。
面試官又問,但是,我們從代碼里面可以看到,check函數接收的這個參數animal的類型是接口類型。那是不是說明接口類型等于鴨子類型?
你一時回答不上來。
面試官又問:那接口類型和鴨子類型是什么關系?鴨子類型是像int、string、map這樣內置的類型嗎?我們可以在 Golang 里面使用var a string 聲明一個類型為string的變量,那請問怎么聲明一個類型為鴨子的變量?
你一時想不起來 Golang 自帶的關鍵詞里面,哪個關鍵詞包含duck這個單詞。
面試官露出了耐克式的微笑,對你說:“回家等通知吧。”
這個討厭的面試官最后一個問題把你難住了。但是這個問題其實是一個陷阱。面試官給你玩了一個文字游戲。當他把鴨子類型和整型、字符串類型合在一起說的時候,讓你覺得鴨子類型也是一種類型。但實際上鴨子類型并不是一種類型,鴨子類型是一種動態類型的風格:
怎么解釋什么叫做設計風格呢?我們再用 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」,可以通過以下二維碼關注。轉載本文請聯系未聞Code公眾號。