跳至內容

鴨仔型別

出自Taiwan Tongues 台語維基
這是此頁批准,以及是最近的修訂。

鴨仔型別(英語:duck typing)佇程式設計中是動態型別的一種風格。佇這種風格內底,一个物件有效的語意,毋是由繼承自特定的類抑是現特定的介面,是由來的「做頭前方法佮屬性的集合」決定。這个概念的名來源於由詹姆斯 ・ 惠特科姆 ・ 萊利提出的鴨仔測試(見下跤的「歷史」章節),「鴨仔測試」會當按呢表述:


「當看著一隻鳥仔行起來鴨仔、游泳起來親像鴨仔、叫起來嘛敢若鴨仔,這隻鳥仔就會當予人叫做鴨仔。」

鴨仔型別中,關注點佇咧物件的行為,會當做啥;毋是關注物件的類型。比如講,佇無使用鴨仔型別項語言內底,咱會當編寫一个函式按呢,伊接受一个類型為「鴨咪」的東西,並呼叫伊的「行」和「叫」方法。佇使用鴨仔型別的語言內底,按呢的一个函式會當接受一个任意類型的物件,並呼叫伊的「行」和「叫」方法。若是這寡需要被呼叫的方法無存在,按呢欲引發一个執行失覺察。任何擁有這樣的正確的「行」和「叫」方法的物件攏會當被函式接受的這種行為引出了以上表述,這種決定類型的方式就按呢出名。

鴨仔型別通常得益於「無」測試方法佮函式內底參數的類型,是依賴的文件、清楚的代碼佮測試來確保正確使用。

佇常的規類型當中,咱敢會當佇一个特定的場景內底用某一个物件決定佇這个物件的類型,啊若佇鴨仔形別當中,著愛看這个物件敢有啥物某種屬性抑是方法—— 即只要有具備特定的屬性抑是方法,會當通過鴨仔試看覓,就會使用。

概念樣例

考慮用佇一个使用鴨仔型別的語言以下虛擬碼:

` ` ` functioncalculate ( a , b , c )=>return( a + b ) * c

example 一=calculate ( 一 , 二 , 三 ) example 二=calculate ( [一 , 二 , 三] , [四 , 五 , 六] , 二 ) example 三=calculate ('apples','and oranges ,', 三 )

'print'to \ _ stringexample 一 'print'to \ _ stringexample 二 'print'to \ _ stringexample 三 ` ` `

佇咧樣例中,逐改著 ` calculate ` 的呼叫攏使用的東西(數字、列表佮字串)繼承關係當中無聯絡。只要物件支援「+」和「\ *」方法,操作就會成功。比如講,翻做 Ruby 抑是 Python 語言,執行結果應該是:

` ` ` 九 [一 , 二 , 三 , 四 , 五 , 六 , 一 , 二 , 三 , 四 , 五 , 六] apples and oranges , apples and oranges , apples and oranges , ` ` `

按呢乎,鴨仔型莫使用繼承的情況下使用濟型。唯一的要求是 ` calculate ` 函式需要做參數的物件有「+」和「\ *」方法。以下樣例(Python 語言)體現鴨仔試看覓。就 ` in _ the _ forest ` 函式來講,物件是一个鴨仔:

靜態語言中的鴨仔型別

一寡通常的靜態語言如 Boo 和 C # 第四版,有一寡加額的類型註解,𪜶指示編譯器將類的型別檢查安排佇執行的時陣毋是編譯的時陣,並且佇咧編譯器的輸出中包括用佇咧執行時型別檢查的代碼。遮的附加的內容允准遮的語言享受鴨仔型別的大多數益處,干焦有的缺點是需要佇咧編譯的時陣辨識佮指定遮的動態類。

佮其他型別系統的較

結構型別系統

鴨仔型別佮結構類型相𫝛毋過佮之無仝。結構類型由類型的結構決定類型的相容性佮等價性,鴨仔型別干焦由結構當中咧執行的時所存取的部份決定類型的相容性。Objective Caml 語言使用結構型別系統。

介面

介面會當提供鴨仔型別的一寡益處,毋過鴨仔型別佮無仝款的是無顯式定義任何介面。比如講,你若一个第三方 Java 庫實現一个使用者無允准修改的類似,使用者就無法度共這个類別的實例用做一个家己定義的介面的實現,鴨仔形毋通允准按呢做。

模板仔抑是泛型

模板函式抑是方法佇一个靜態型別頂下文中應用鴨仔試驗;這个同時帶來著靜態佮動態型別檢查的一般優點佮欠點。同時,因為鴨仔型別當中,只有「咧執行的時予實際呼叫的」方法需要予實現,而且板仔要求實現「咧編譯的時陣袂當證明不可到的」所有的方法,因此鴨仔型別閣較有會伸勼性。

實例包括紮著模仔的 C + + 語言佮 Java 語言的泛型。

批評

關於鴨仔型別常在予人參照的一个批評是伊要求程式設計師伊佇任何時陣攏著愛足好的理解伊 / 伊當咧編寫的代碼。佇一个強靜態型別的、使用矣類型繼承樹仔佮參數型別檢查的語言內底,予一个類提供無預測的物件類型閣較為困難。比如講,佇咧 Python 中,你會當建立一个叫做 Wine 的類似,並且佇內底需要實現 press 方法。毋過,一个叫做 Trousers 的類可能嘛實現 press ( ) 方法。為著避免奇怪的、真歹檢測的錯誤,開發者咧使用鴨仔型別時需要意識著每一个「press」方法的可能使用,就算講佇語意上和伊 / 伊所當咧編寫工課的代碼無任何的關係。

本質上,問題是:「 若伊行起來像鴨仔並且叫起來像鴨仔」,伊嘛會當是一隻當咧模仿鴨仔的龍。就算講𪜶會當模仿鴨仔,但是你無總是想欲予龍進入池仔。

鴨仔型別个提倡者,如吉濟 ・ 范羅蘇姆,認為這个問題會當通過咧試佮維護代碼庫頭前有夠額的了解來解決。

對鴨仔型別款批評傾向來成做關於動態型別佮靜態型別的爭論的較闊的觀點的特殊情形。

歷史

Alex Martelli 足早(二空空空年)就咧發布到 comp . lang . python 新聞群組的一个訊息中使用了這一術語。伊同時對鴨仔試的錯誤的字面理解提出了提醒,以避免人錯誤認為這个術語已經予人使用。


「換言之,莫共伊檢查著無一个鴨仔:共檢查有成無一个鴨仔地,等咧。就決定你需要啥物像鴨仔的行為的子集來使用語言。」

實現

佇咧 ColdFusion 中

web 應用程式手稿語言 ColdFusion 允准函式參數被指定做類型為 _ any _。對這種參數,任意物件攏會當予傳入去,函式呼叫咧執行的時被動態結束。若是物件無實現一个被呼叫的函式,一个會用被揣取閣優雅的處理的執行各樣各樣被擲捒。佇咧 ColdFusion 八中,這嘛會當予一个定義的事件 onMissingMethod ( ) 毋是例外處理器處理。一个會當代替參數類型 _ WEB-INF . cftags . component _ 限制傳來到參數是一个 ColdFusion 組件(CFC), 佇咧無正確的物件傳入去的時伊提供了閣較好的錯誤訊息。

佇咧 C # 中

C # 四配零實現了動態成員查詢(dynamic member lookup)實現鴨仔型別化。注意下例中類別步數 InTheForest 的參數類型予人聲明為 dynamic。

佇咧 Common Lisp 中

Common Lisp 提供一个物件導向的擴充(Common Lisp 東西系統,簡寫為 CLOS)。 佇咧 Common Lisp 中,CLOS 和 Lisp 的動態型別使鴨仔型別成做一種通用的編程風格。

使用 Common Lisp,使用者通常毋免查詢類型,因為若一个函式無適用,系統會擲一个執行失覺察。這个錯誤會當予 Common Lisp 的條件系統處理。佇咧類外定義的方法嘛會當替指定的物件定義。

Common Lisp 通常的開發風格(像 SLIME 仝款使用 Lisp REPL)無定著互動式修復:

通過這種方法,軟體會當通過擴充干焦部份工作的使用鴨仔型別的代碼來開發。

佇咧 Objective-C 中

Objective-C,C 和 Smalltalk 的一个交含,像 Smalltalk 仝款,允准使用者聲明一个物件的類型做「id」閣向伊傳送任何的資訊。傳送者會當測試一个物件以了解伊會當對一个訊息回應,物件會當佇收著訊息的時陣決定回應佮,假使傳送者傳送一个接收者袂當回應的訊息,一个異常會去予人擲捒。所以,鴨仔型別佇 Objective-C 中予人完全支援。

佇咧 Python 中

鴨仔型別佇 Python 中被廣泛使用。Python 術語表按呢定義鴨仔型別:

佇咧 Python 中,鴨仔型別的上典型例就是類似 file 的類似。這類會當實現 ` file ` 的一寡抑是全部的方法,並會當用於 ` file ` 通常使用的所在。比如講,` GzipFile ` 實現一个用於存取 gzip 壓縮的資料的類似 file 的東西。` cStringIO ` 允准共一个 Python 字串視作一个檔案。通訊端(socket)也和檔案共同有誠濟仝款的方法。毋過通訊端欠缺 ` tell ( ) ` 方法,袂使用著 ` GzipFile ` 會當使用的所在。這體咱這个鴨仔型別款會伸勼性:一个類似 file 的物件會當實現伊有能力實現的方法,而且干焦會當予伊有意義的情形下。

EAFP 原則講著例外處理的使用。譬如講相對檢查一个自稱做類似 Duck 的物件敢有算一个 _ quack ( ) _ 方法(使用 ` if hasattr ( mallard , " quack " ) : . . . `), 人通常閣較傾向用例外處理共對 _ quack _ 的呼叫欲試包裹起來:

這个寫法的優勢佇咧鼓勵結構化處理其他來自類的錯誤(若按呢,比如講,一个袂當完成 quack 的 Duck 子類會當擲一个桮「QuackException」,這个異常會當簡單來添加到包裹伊的代碼,並無需要影響閣較濟的代碼的邏輯。同時,對其他無仝類的物件存在無相容的成員造成的號名衝突,伊原仔會當處理(比如講,準講有一个醫學專家 Mallard 有一个布林屬性將伊分類「quack=True」,試圖執行 Mallard . quack ( ) 將擲一个 TypeError)。

佇閣較實際的實現類似 file 的行為的例內底,人閣較傾向使用 Python 的例外處理機制來處理各種各樣的可能各種程式設計師無法度控制的環境佮作業系統問題發生的 I / O 錯誤。佇遮,「 鴨仔型別」產生的異常會用佇𪜶家己的子句中揣,佮作業系統、I / O 佮其他可能的錯誤分別處理,對而且避開複雜的檢測佮錯誤檢查邏輯。

參考文獻

參閱

  • 鴨仔測試 ( duck test )

外部連結

  • Duck Typing : Ruby
  • How to duck type ?-the psychology of static typing in Ruby
  • Python 術語表內底的 duck-typing 詞條
  • Dr . Dobbs June 一兩千空五 : " Templates and Duck Typing "
  • Javascript'typeof'limitations and duck typing
  • Python from a Java perspective-Part 二-How duck typing influences class design and design principles