摘要:許多編程語言都支持,通常是動態編程語言用來實現多態的一種方式。在編程中,也常常用這種方式來描述事物。那么不同的編程語言中,是怎么樣實現的呢中的先看一個函數有一個函數,傳過來一個參數,是可以獲取一個鏈接的資源的。
如果一只動物走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么這只動物就可以被稱為鴨子。
許多編程語言都支持 Duck Typing ,通常 Duck Typing 是動態編程語言用來實現多態的一種方式。
在理解 Duck Typing 前,先看一張圖片,這是曾經一度很火的大黃鴨
先問一個比較考三觀的問題:圖片中的大黃鴨,它是不是一只鴨子呢?
這個問題,得看你從哪個角度去看,如果從人們常識的認知中的角度去看,它顯然不是一只鴨子,因為它連最基本的生命都沒有。
但是從 Duck Typing 的角度來看,它就是一只鴨子!
Duck Typing 的原話是,走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么它就是一只鴨子。
這個原話是可以靈活理解的,就看我們怎么定義鴨子的行為,我們可以說,能浮在水上游的,黃色的,可愛的就是鴨子,那么,圖片中的大黃鴨,它就是一只鴨子!
這就是所謂的 Duck Typing,它只關心事物的外部行為而非內部結構。它并不關心你這只鴨子是長肉的還是充氣的。
在編程中,也常常用這種方式來描述事物。那么不同的編程語言中,Duck Typing 是怎么樣實現的呢?
1. Python 中的 Duck Typing
先看一個函數:
def download(fetcher): return fetcher.get("http://xxx");
有一個 download 函數,傳過來一個 fetcher 參數,fetcher 是可以獲取一個 url 鏈接的資源的。
這個 fetcher 就是一個 Duck Typing 的對象,使用者約定好這個 fetcher 會有一個 get 函數就可以了。
顯然這個 download 函數會有以下問題:
運行時才知道傳入的 fetcher 有沒有 get 函數。那么站在 download 函數的使用者的角度上看,我怎么知道需要給 fetcher 實現 get 方法呢?我不可能去閱讀 download 函數的代碼,實際情況中,可能 download 函數的代碼很長,可能 fetcher 不只要實現 get 方法,還有其它方法需要實現。通常這種情況需要通過加注釋來說明。
2. C++ 中的 Duck Typing
C++ 不是動態語言,但是它也能支持 Duck Typing,它是通過模板來支持的。
示例代碼:
templatestring download(const F& fetcher){ return fetcher.get("http://xxxx") }
這段代碼與 Python 的實現方法類似,這個 fetcher 隨便什么類型都可以,只要實現一個 get 方法,就能通過編譯。
那么這種實現方法有什么缺點呢,就是,編譯時,才知道傳入的 fetcher 有沒有 get 方法。
但它比 python 好一點了,python 是運行時才知道,C++ 是編譯時就知道。
同樣,這種情況,還是需要注釋來說明。
3. Java 中的類似代碼
Java 沒有 Duck Typing,它只有類似的代碼。Java 的 duck typing :
String download(F fetcher){ return fetcher.get("http://xxxx") }
它同樣也用了模板類型。模板 F 必須 extends FetcherInterface ,有了這個限定,就能逼著 download 函數的使用者對 fetcher 實現 get 方法,它解決了需要注釋來說明的缺點。
傳入的參數必須實現 FetcherInterface 接口,就沒有運行時發現錯誤,編譯時發現錯誤的問題。
但是,它嚴格上來說不是 Duck Typing 。
如果 download 函數只依賴 fetcher 的 get 方法,而 FetcherInterface 接口必須要實現除 get 方法以外,還有其它方法,那么也要一一實現,非常不靈活。
4. Go 中的 Duck Typing
在 Java 的 Duck Typing 類似代碼中,如果 fetcher 參數需要同時實現兩個或以上的接口方法時,Java 是沒有辦法做到的。但 Go 語言可以做到。
type Fetcher interface { Get(url string) string } type Saver interface { Save(content string) } type FetcherAndSaver interface { Fetcher Saver } func download(f Fetcher) string { return f.Get("http://xxxx") } func save(f saver) { f.Save("some thing") } func downloadAndSave(f FetcherAndSaver) { content := f.Get("http://xxxx") f.Save(content) } # 實現者 type MyFetcherAndSaver struct { } func (f MyFetcherAndSaver) Get(url string) string { ... } func (f MyFetcherAndSaver) Save(content string) { ... } func main() { f := MyFetcherAndSaver{} download(f) save(f) downloadAndSave(f) }
這里定義了三個接口,只要有 Get 方法的就是 Fetcher,只要有 Save 方法的就是 Saver,同時有 Get 方法和 Save 方法就是 FetcherAndSaver 。
實現者 MyFetcherAndSaver 并不需要聲明它實現了哪些接口,只要它有相關接口的所定義的方法,那么它的實例,就即能作為 Fetcher 接口來使用,又能作為 Saver 接口來使用,也能作為 FetcherAndSaver 接口來使用。
Go 的實現方法相對比較靈活,又不失類型檢查。總的來說,特點有:
即能同時實現多個接口
又具有 python , C++ 的 Duck Typing 靈活性
又具有 java 的類型檢查。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/75038.html
摘要:許多編程語言都支持,通常是動態編程語言用來實現多態的一種方式。在編程中,也常常用這種方式來描述事物。那么不同的編程語言中,是怎么樣實現的呢中的先看一個函數有一個函數,傳過來一個參數,是可以獲取一個鏈接的資源的。 如果一只動物走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么這只動物就可以被稱為鴨子。 許多編程語言都支持 Duck Typing ,通常 Duck Typing 是動態編程...
摘要:有一些定制類的特殊方法,如,其中一些具有動態特性的方法可以用來很方便地處理某些動態狀況。動態化屬性和方法的調用,當調用不存在的屬性時,如果存在方法,就會調用方法來嘗試獲得屬性。這種完全動態的調用可以應對一些動態情況,例如實現。 Python有一些定制類的特殊方法,如__str__()、__iter__()、__getitem__(),其中一些具有動態特性的方法可以用來很方便地處理某些動...
摘要:本文已收錄修煉內功躍遷之路我們寫的方法在被編譯為文件后是如何被虛擬機執行的對于重寫或者重載的方法,是在編譯階段就確定具體方法的么如果不是,虛擬機在運行時又是如何確定具體方法的方法調用不等于方法執行,一切方法調用在文件中都只是常量池中的符號引 本文已收錄【修煉內功】躍遷之路 showImg(https://segmentfault.com/img/bVbuesq?w=2114&h=12...
摘要:類型檢測在中提供兩種檢測類型的方法,但是它們并不總是靠譜。引用類型引用類型使用檢測,返回都是。這個時候可以用,它的語法是實例對象構造函數不僅能檢測構造對象的構造器,還檢測原型鏈。 類型檢測 在js中提供兩種檢測類型的方法,但是它們并不總是靠譜。 typeof instanceof 下面我們來看看各個類型的應該如何進行檢測比較靠譜 1. 基本類型 基本類型(除null之外)的檢測使用...
摘要:本文重點協議是中非正式的接口了解抽象基類的基本概念以及標準庫中的抽象基類掌握抽象基類的使用方法。三抽象基類的使用通過繼承聲明抽象基類聲明抽象基類最簡單的方式是繼承或其他抽象基類注意在之間,繼承抽象基類的語法是。 導語:本文章記錄了本人在學習Python基礎之面向對象篇的重點知識及個人心得,打算入門Python的朋友們可以來一起學習并交流。 本文重點: 1、協議是Python中非正式的接...
閱讀 1856·2023-04-25 14:28
閱讀 1892·2021-11-19 09:40
閱讀 2795·2021-11-17 09:33
閱讀 1385·2021-11-02 14:48
閱讀 1710·2019-08-29 16:36
閱讀 3333·2019-08-29 16:09
閱讀 2917·2019-08-29 14:17
閱讀 2378·2019-08-29 14:07