2013-10-03 78 views
8

我正在學習Ruby,我有一個關於打字的重大概念問題。請允許我詳細說明爲什麼我不瞭解範式。如何使用Ruby Duck Typing

假設我是Ruby中的簡潔代碼的方法鏈接。我必須精確地知道鏈中每個方法調用的返回類型,否則我不知道下一個鏈接上有哪些方法可用。我每次都必須檢查方法文檔嗎?我遇到了這個不斷運行的教程練習。看來我堅持一個參考過程,推斷,運行,失敗,修復,重複以獲得代碼運行,而不是知道我在編碼期間正在處理的內容。這在Ruby的直覺性承諾面前飛來飛去。

說我正在使用第三方庫,我再一次需要知道哪些類型允許傳遞參數,否則我會失敗。我可以看看代碼,但是可能會有也可能沒有任何關於該方法所期待的類型的評論或聲明。我理解你基於方法的代碼是可用的對象,而不是類型。但是,我必須確定無論我傳遞的參數是否具有庫所需的所有方法,所以我仍然需要進行類型檢查。我是否希望並祈禱一切都在接口上正確記錄,以便我知道是否需要給出字符串,哈希,類等。

如果我查看方法的來源,我可以得到一個被調用的方法列表並推斷出預期的類型,但我必須執行分析。

Ruby and duck typing: design by contract impossible?

在前面的計算器問題的討論沒有真正回答不是「有你必須遵循流程」和這些進程似乎並不爲標準的其它任何東西,每個人都有不同的意見遵循什麼程序,以及該語言的執行力度爲零。方法驗證?測試驅動設計?記錄的API?嚴格的方法命名約定?標準是什麼,誰決定它?我遵循什麼?這些指導方針是否可以解決這個問題https://stackoverflow.com/questions/616037/ruby-coding-style-guidelines?有編輯幫忙嗎?

從概念上講,我也沒有得到好處。您需要知道所調用的任何方法需要哪些方法,因此無論您在編寫任何代碼時都正在輸入內容。除非您決定對其進行記錄,否則您只是沒有明確告知該語言或任何其他人。然後,你被困在做所有類型檢查在運行時而不是在編碼過程中。我已經完成了PHP和Python編程,但我也不明白。

我錯過了什麼或不理解?請幫我理解這個範例。

+2

鴨子打字有一定的優勢,但當然也有缺點。我可以將* any *對象傳遞給一個方法'foo(a)',它只要調用'a.responds_to?(:bar)'就可以調用'a.bar'。這很好。沒有界面,沒有泛型,只需添加一個'bar'方法即可。當然,靜態打字也有很多優點。聽起來你只需要一些Ruby方式的經驗來欣賞兩者。也聽起來像你可能被intellisense(或類似的功能)有點被寵壞了。許多(*許多*)我們必須儘早且經常地檢查文檔。 –

+2

直覺是訓練的結果,所以沒有直覺,直到你訓練自己使用它。 –

+0

這個問題患有「TL; DR」。它會幫助你總結它,並拋棄其他方面,否則它太廣泛了。 「這直接面對Ruby對直覺的承諾。」對誰是直觀的? Matz說,它的設計對他來說很直觀,而且他認爲對於那些已經充分使用它的人來說,這會變得直觀。創建一種立即對所有人都直觀的語言是不可能的,所以他的目標就是點亮。 –

回答

1

是的,你似乎誤解了這個概念。它不是靜態類型檢查的替代品。這只是不同。例如,如果您將對象轉換爲json(將它們呈現給客戶端),那麼只要它具有#to_json方法,則不關心對象的實際類型。在Java中,您必須創建IJsonable接口。在紅寶石中,不需要額外的開銷。

至於知道什麼傳遞什麼,什麼返回什麼:記住這個或每次諮詢文檔。我們都這樣做。

又一天,我看到有6年以上的使用經驗的rails程序員在twitter上抱怨說,他無法記憶alias_method的參數順序:新名字先走還是後走?

這就是Ruby面對直覺的承諾。

不是真的。也許這只是寫得不好的圖書館。在覈心ruby中,我敢說,一切都很直觀。

靜態類型與他們強大的IDE語言在這裏有一個小的優勢,因爲他們可以在這裏展示您的文檔,非常快。不過,這仍然在訪問文檔。只有更快。

+1

我認爲你已經接近我的目標了。正如你所說,你會聲明IJsonable。在Ruby中你不會聲明這一點。那麼你怎麼知道你需要這個接口?正如你所說,你必須查閱文檔,文檔必須聲明你需要這個接口,否則沒有檢查代碼就無法知道。那麼有什麼好處,你必須在文檔中聲明,爲什麼不用代碼聲明它,然後你的IDE知道接口,並且可以爲你自動實現事情。什麼是聲明你的界面的開銷。 – kamegami

+0

接口的開銷是系統中的另一個實體。這個你遇到麻煩的圖書館是什麼?大部分與我一起工作的,他們都接受基元(字符串,數組,哈希等)(這在文檔中是顯而易見的)或來自同一個庫的對象(它們再次被記錄)。 –

+0

如果您給某個方法提供了錯誤的對象,則會引發錯誤。這將通過測試來檢測。 –

4

這不是Ruby特定的問題,對於所有動態類型的語言都是一樣的。

通常有對如何可以記錄這個(和大部分時間不是真的有可能)沒有準則。紅寶石文檔

map { |item| block } → new_ary 
map → Enumerator 

什麼是itemblocknew_ary這裏,他們如何在相關見例如map?除非你知道實現或者可以以某種方式從函數的名稱推斷它,否則無法分辨。指定類型也很困難,因爲new_ary取決於block返回的內容,而這又取決於item的類型,這對於陣列中的每個元素可能都不相同。

很多時候你還偶然發現的文件,指出一種說法是Object類型,這再次告訴你什麼,因爲一切都是對象的。

OCaml爲此提供了一個解決方案,它支持結構打字,因此需要一個屬性爲foo的對象的函數String將被推斷爲{ foo : String }而不是具體類型。但OCaml仍然是靜態類型的。

值得注意的是,這也可能是靜態類型的lanugages中的問題。 Scala對集合有非常通用的方法,導致類型簽名如++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Array[T], B, That]): That用於追加兩個集合。

所以大多數的時候,你就只能通過心臟的動態類型語言學習這,或許有助於提高您使用的庫文件。

這就是爲什麼我喜歡靜態類型;)

編輯一兩件事,可能是有意義的是做什麼斯卡拉也做。它實際上並未向您顯示++的類型簽名默認情況下,它顯示++[B](that: GenTraversableOnce[B]): Array[B]這不是通用的,但可能涵蓋大部分用例。所以對於Ruby的地圖,它可以有一個單形簽名,如Array<a> -> (a -> b) -> Array<b>。對於列表只包含一個類型值並且該塊只返回另一個類型的元素的情況,這只是正確的,但它更容易理解,並且很好地概述了該函數的功能。

+0

您已經擊中了頭部,這是我確切的問題。 – kamegami

2

考慮到強類型語言的設計選擇(C++,Java和C#等)執行傳遞給方法的類型嚴格的聲明,並通過鍵入方法返回。這是因爲這些語言被設計用於驗證參數是否正確(並且由於這些語言被編譯,所以這個工作可以在編譯時完成)。但是有些問題只能在運行時回答,例如C++有RTTI(運行時類型解釋器)來檢查和執行類型保證。但是作爲開發人員,您將受到語法,語義和編譯器的指導,以生成遵循這些類型約束的代碼。

Ruby使您可以靈活地採取動態參數類型並返回動態類型。這種自由使你能夠編寫更通用的代碼(在STL和泛型編程中讀取Stepanov),併爲你提供了一套豐富的自省方法(is_a?,instance_of?,respond_to?,kind_of?,is_array?等)可以動態使用。 Ruby使您能夠編寫通用方法,但您也可以通過合同強制執行設計,並通過選擇的方式處理合同失敗。

是的,你需要鏈接方法時在一起,但學習Ruby不僅僅是一些新的關鍵字來照顧。 Ruby支持多種範例;你可以編寫程序,對象oriend,通用和功能程序。當你瞭解Ruby時,你現在正在使用的循環會很快得到改善。

也許你的關注從對強類型語言(C++,Java和C#等)偏置莖。鴨子打字是一種不同的方法。你有不同的想法。鴨子打字意味着,如果一個物體看起來像一個,行爲像一個,那麼它是一個。一切(幾乎)都是Ruby中的一個對象,所以一切都是多態的。

考慮模板(C++有他們,C#有他們,Java正在讓他們,C具有宏)。您構建算法,然後讓編譯器爲您選擇的類型生成實例。你不是通過與泛型合同進行設計,但是當你認識到他們的力量時,你可以編寫更少的代碼,並且產生更多的代碼。

你的一些其他問題,

  • 第三方庫(寶石),是不是很難,因爲你害怕
  • 說明的API使用?見RDOC和http://www.ruby-doc.org/
  • RDoc文檔(通常)提供的庫
  • 編碼準則 - 看看源對於初學者
  • 命名約定的幾個簡單的寶石 - 蛇情況和駱駝都流行

建議 - 接近一個在線教程,以開放的心態,做教程(http://rubymonk.com/learning/books/好),你將有更集中的問題。

+0

這似乎是我正在尋找的答案。所以我應該通過對參數進行適當的運行時檢查來執行自檢。然後你必須生成文檔來代替類型或接口聲明。文檔是否可以通過內省檢查生成?如果說PEP8相當於指出並說「這樣做是錯誤的」,那麼我會覺得更加自在。 – kamegami

+0

@ kamegami:Ruby的內省不會從代碼中發現預期的類型,所以無法在沒有幫助的情況下生成完整的文檔。但是,諸如'yard'之類的doc工具允許編碼人員爲params聲明類型並返回值。因此你依靠圖書館開發者的良好意圖和文檔。如果你有時間和傾向,可以寫出非常全面和準確的文件。 –

+0

似乎是否有用於聲明參數意圖的標準約定(我將調用具有您期望的接口的對象),您可以在一次犯規中處理接口文檔,錯誤處理和IDE靜態意圖分析(Intellisense風格)一舉。我不能成爲唯一一個認爲這是動態類型語言的人。 – kamegami