<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 潛在類型機制 在本章的開頭介紹過這樣的思想,即要編寫能夠盡可能廣泛地應用的代碼。為了實現這一點,我們需要各種途徑來放松對我們的代碼將要作用的類型所作的限制,同時不丟失靜態類型檢查的好處。然后,我們就可以編寫出無需修改就可以應用于更多情況的代碼,即更加“泛化”的代碼。 Java 泛型看起來是向這一方向邁進了一步。當你在編寫或使用只是持有對象的泛型時,這些代碼將可以工作于任何類型(除了基本類型,盡管正如你所見到的,自動裝箱機制可以克服這一點)。或者,換個角度講,“持有器”泛型能夠聲明:“我不關心你是什么類型”。如果代碼不關心它將要作用的類型,那么這種代碼就可以真正地應用于任何地方,并因此而相當泛化。 還是正如你所見到的,當要在泛型類型上執行操作(即調用 **Object** 方法之外的方法)時,就會產生問題。擦除強制要求指定可能會用到的泛型類型的邊界,以安全地調用代碼中的泛型對象上的具體方法。這是對“泛化”概念的一種明顯的限制,因為必須限制你的泛型類型,使它們繼承自特定的類,或者實現特定的接口。在某些情況下,你最終可能會使用普通類或普通接口,因為限定邊界的泛型可能會和指定類或接口沒有任何區別。 某些編程語言提供的一種解決方案稱為*潛在類型機制*或*結構化類型機制*,而更古怪的術語稱為*鴨子類型機制*,即“如果它走起來像鴨子,并且叫起來也像鴨子,那么你就可以將它當作鴨子對待。”鴨子類型機制變成了一種相當流行的術語,可能是因為它不像其他的術語那樣承載著歷史的包袱。 泛型代碼典型地只能在泛型類型上調用少量方法,而具有潛在類型機制的語言只要求實現某個方法子集,而不是某個特定類或接口,從而放松了這種限制(并且可以產生更加泛化的代碼)。正由于此,潛在類型機制使得你可以橫跨類繼承結構,調用不屬于某個公共接口的方法。因此,實際上一段代碼可以聲明:“我不關心你是什么類型,只要你可以 `speak()` 和 `sit()` 即可。”由于不要求具體類型,因此代碼就可以更加泛化。 潛在類型機制是一種代碼組織和復用機制。有了它,編寫出的代碼相對于沒有它編寫出的代碼,能夠更容易地復用。代碼組織和復用是所有計算機編程的基本手段:編寫一次,多次使用,并在一個位置保存代碼。因為我并未被要求去命名我的代碼要操作于其上的確切接口,所以,有了潛在類型機制,我就可以編寫更少的代碼,并更容易地將其應用于多個地方。 支持潛在類型機制的語言包括 Python(可以從 www.Python.org 免費下載)、C++、Ruby、SmallTalk 和 Go。Python 是動態類型語言(幾乎所有的類型檢查都發生在運行時),而 C++ 和 Go 是靜態類型語言(類型檢查發生在編譯期),因此潛在類型機制不要求靜態或動態類型檢查。 ### pyhton 中的潛在類型 如果我們將上面的描述用 Python 來表示,如下所示: ```python # generics/DogsAndRobots.py class Dog: def speak(self): print("Arf!") def sit(self): print("Sitting") def reproduce(self): pass class Robot: def speak(self): print("Click!") def sit(self): print("Clank!") def oilChange(self): pass def perform(anything): anything.speak() anything.sit() a = Dog() b = Robot() perform(a) perform(b) output = """ Arf! Sitting Click! Clank! """ ``` Python 使用縮進來確定作用域(因此不需要任何花括號),而冒號將表示新的作用域的開始。“**#**” 表示注釋到行尾,就像Java中的 “ **//** ”。類的方法需要顯式地指定 **this** 引用的等價物作為第一個參數,按慣例成為 **self** 。構造器調用不要求任何類型的“ **new** ”關鍵字,并且 Python 允許普通(非成員)函數,就像 `perform()` 所表明的那樣。注意,在 `perform(anything)` 中,沒有任何針對 **anything** 的類型,**anything** 只是一個標識符,它必須能夠執行 `perform()` 期望它執行的操作,因此這里隱含著一個接口。但是你從來都不必顯式地寫出這個接口——它是潛在的。`perform()` 不關心其參數的類型,因此我可以向它傳遞任何對象,只要該對象支持 `speak()` 和 `sit()` 方法。如果傳遞給 `perform()` 的對象不支持這些操作,那么將會得到運行時異常。 輸出規定使用三重引號創建帶有內嵌換行符的字符串。 ### C++ 中的潛在類型 我們可以用 C++ 產生相同的效果: ```c++ // generics/DogsAndRobots.cpp #include <iostream> using namespace std; class Dog { public: void speak() { cout << "Arf!" << endl; } void sit() { cout << "Sitting" << endl; } void reproduce() {} }; class Robot { public: void speak() { cout << "Click!" << endl; } void sit() { cout << "Clank!" << endl; } void oilChange() {} }; template<class T> void perform(T anything) { anything.speak(); anything.sit(); } int main() { Dog d; Robot r; perform(d); perform(r); } /* Output: Arf! Sitting Click! Clank! */ ``` 在 Python 和 C++ 中,**Dog** 和 **Robot** 沒有任何共同的東西,只是碰巧有兩個方法具有相同的簽名。從類型的觀點看,它們是完全不同的類型。但是,`perform()` 不關心其參數的具體類型,并且潛在類型機制允許它接受這兩種類型的對象。 C++ 確保了它實際上可以發送的那些消息,如果試圖傳遞錯誤類型,編譯器就會給你一個錯誤消息(這些錯誤消息從歷史上看是相當可怕和冗長的,是 C++ 的模版名聲欠佳的主要原因)。盡管它們是在不同時期實現這一點的,C++ 在編譯期,而 Python 在運行時,但是這兩種語言都可以確保類型不會被誤用,因此被認為是強類型的。潛在類型機制沒有損害強類型機制。 ### Go 中的潛在類型 這里用 Go 語言編寫相同的程序: ```go // generics/dogsandrobots.go package main import "fmt" type Dog struct {} func (this Dog) speak() { fmt.Printf("Arf!\n")} func (this Dog) sit() { fmt.Printf("Sitting\n")} func (this Dog) reproduce() {} type Robot struct {} func (this Robot) speak() { fmt.Printf("Click!\n") } func (this Robot) sit() { fmt.Printf("Clank!\n") } func (this Robot) oilChange() {} func perform(speaker interface { speak(); sit() }) { speaker.speak(); speaker.sit(); } func main() { perform(Dog{}) perform(Robot{}) } /* Output: Arf! Sitting Click! Clank! */ ``` Go 沒有 **class** 關鍵字,但是可以使用上述形式創建等效的基本類:它通常不定義為類,而是定義為 **struct** ,在其中定義數據字段(此處不存在)。 對于每種方法,都以 **func** 關鍵字開頭,然后(為了將該方法附加到您的類上)放在括號中,該括號包含對象引用,該對象引用可以是任何標識符,但是我在這里使用 **this** 來提醒您,就像在 C ++ 或 Java 中的 **this** 一樣。 然后,在Go中像這樣定義其余的函數。 Go也沒有繼承關系,因此這種“面向對象的目標”形式是相對原始的,并且可能是我無法花更多的時間來學習該語言的主要原因。 但是,Go 的組成很簡單。 `perform()` 函數使用潛在類型:參數的確切類型并不重要,只要它包含了 `speak()` 和 `sit()` 方法即可。 該接口在此處匿名定義,內聯,如 `perform()` 的參數列表所示。 `main()` 證明 `perform()` 確實對其參數的確切類型不在乎,只要可以在該參數上調用 `talk()` 和 `sit()` 即可。 但是,就像 C ++ 模板函數一樣,在編譯時檢查類型。 語法 **Dog {}** 和 **Robot {}** 創建匿名的 **Dog** 和 **Robot** 結構。 ### java中的直接潛在類型 因為泛型是在這場競賽的后期才添加到 Java 中,因此沒有任何機會可以去實現任何類型的潛在類型機制,因此 Java 沒有對這種特性的支持。所以,初看起來,Java 的泛型機制比支持潛在類型機制的語言更“缺乏泛化性”。(使用擦除來實現 Java 泛型的實現有時稱為第二類泛型類型)例如,在 Java 8 之前如果我們試圖用 Java 實現上面 dogs-and-robots 的示例,那么就會被強制要求使用一個類或接口,并在邊界表達式中指定它: ```java // generics/Performs.java public interface Performs { void speak(); void sit(); } ``` ```java // generics/DogsAndRobots.java // No (direct) latent typing in Java import typeinfo.pets.*; class PerformingDog extends Dog implements Performs { @Override public void speak() { System.out.println("Woof!"); } @Override public void sit() { System.out.println("Sitting"); } public void reproduce() {} } class Robot implements Performs { public void speak() { System.out.println("Click!"); } public void sit() { System.out.println("Clank!"); } public void oilChange() {} } class Communicate { public static <T extends Performs> void perform(T performer) { performer.speak(); performer.sit(); } } public class DogsAndRobots { public static void main(String[] args) { Communicate.perform(new PerformingDog()); Communicate.perform(new Robot()); } } /* Output: Woof! Sitting Click! Clank! */ ``` 但是要注意,`perform()` 不需要使用泛型來工作,它可以被簡單地指定為接受一個 **Performs** 對象: ```java // generics/SimpleDogsAndRobots.java // Removing the generic; code still works class CommunicateSimply { static void perform(Performs performer) { performer.speak(); performer.sit(); } } public class SimpleDogsAndRobots { public static void main(String[] args) { CommunicateSimply.perform(new PerformingDog()); CommunicateSimply.perform(new Robot()); } } /* Output: Woof! Sitting Click! Clank! */ ``` 在本例中,泛型不是必需的,因為這些類已經被強制要求實現 **Performs** 接口。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看