複製鏈接
請複製以下鏈接發送給好友

通用代碼

鎖定
通用代碼,也叫通用編程,是一種計算機編程風格,其中算法是根據待指定的類型編寫的,然後在需要時作為參數提供的特定類型進行實例化。 這種方法由ML於1973年開創,允許編寫僅在使用時操作的類型集不同的共同功能或類型,從而減少重複。 這些軟件實體在Ada,C#, Delphi,Eiffel,F#,Java,Rust,Swift,TypeScript和Visual Basic .NET中稱為泛型。 它們被稱為ML,Scala,Haskell中的參數多態性(Haskell社區也使用術語“泛型”用於相關但有些不同的概念)和Julia; C ++和D中的模板; 有影響力的1994年着作“設計模式”中的參數化類型。設計模式的作者注意到這種技術,特別是與委託相結合時,非常強大,但是,
中文名
通用代碼
又    叫
通用編程

通用代碼通用性

至少在20世紀70年代,通用設施已經存在於ML,CLU和Ada等語言中,並且隨後被許多基於對象和麪向對象的語言所採用,包括BETA,C ++,D,Eiffel,Java,和DEC已經不復存在的Trellis-Owl語言。
在各種編程語言中以不同方式實現和支持通用性;術語“通用”在各種編程環境中也被不同地使用。例如,在Forth中,編譯器可以在編譯時執行代碼,並且可以動態地為這些單詞創建新的編譯器關鍵字和新實現。它幾乎沒有暴露編譯器行為的單詞,因此自然地提供了通用性能力,然而,在大多數Forth文本中並未提及這些能力。類似地,動態類型語言,特別是解釋型語言,默認情況下通常提供通用性,因為向函數和值賦值傳遞值都是類型無關緊要的,並且這種行為通常用於抽象或代碼簡潔,但是這通常不是標記為通用性,因為它是語言所採用的動態類型系統的直接後果。該術語已用於函數式編程,特別是在類似Haskell的語言中,它使用結構類型系統,其中類型總是參數化的,並且這些類型上的實際代碼是通用的。這些用法仍然用於代碼保存和抽象呈現的類似目的。
可以將數組和結構視為預定義的泛型類型。數組或結構類型的每次使用都會實例化一個新的具體類型,或者重用先前實例化的類型。數組元素類型和結構元素類型是參數化類型,用於實例化相應的泛型類型。所有這些通常都內置在編譯器中,語法與其他通用結構不同。一些可擴展的編程語言嘗試統一內置和用户定義的泛型類型。

通用代碼面向對象的代碼

在使用靜態類型語言創建容器類時,為每個包含的數據類型編寫特定實現是不方便的,特別是如果每個數據類型的代碼實際上是相同的。 例如,在C ++中,可以通過定義類模板來規避這種代碼重複:
template<typename T>
class List
{   /* class contents */
};
List<Animal> list_of_animals;
List<Car> list_of_cars;
在上面,T是佔位符,用於創建列表時指定的任何類型。 這些“tank-of-type-T”(通常稱為模板)允許使用不同的數據類型重用類,只要保留某些合同(如子類型和簽名)即可。 這種通用性機制不應與包含多態性相混淆,包含多態性是可交換子類的算法用法:例如,包含類型為Animal和Car的對象的Moving_Object類型的對象列表。 模板也可用於與類型無關的功能,如下面的Swap示例所示:
template<typename T>
void Swap(T & a, T & b) //"&" passes parameters by reference
{   T temp = b;   b = a;   a = temp;
}
string hello = "World!", world = "Hello, ";
Swap( world, hello );
cout << hello << world << endl;//Output is "Hello, World!"
上面使用的C ++模板構造被廣泛引用[引用需要]作為通用性構造,在程序員和語言設計者之間普及概念並支持許多通用編程習語。 D編程語言還提供了基於C ++先例但具有簡化語法的完全通用的模板。 自J2SE 5.0引入以來,Java編程語言在語法上提供了基於C ++的通用性設施。
C#2.0,Oxygene 1.5(也稱為Chrome)和Visual Basic .NET 2005具有利用自2.0版以來對Microsoft .NET Framework中存在的泛型的支持的構造。

通用代碼用C ++進行擴展

C ++使用模板來啓用通用編程技術。 C ++標準庫包括標準模板庫或STL,它為常見的數據結構和算法提供模板框架。 C ++中的模板也可用於模板元編程,這是一種在編譯時而不是運行時預先評估某些代碼的方法。 使用模板專業化,C ++模板被認為是圖靈完整的。

通用代碼D中的模板

D編程語言支持基於C ++設計的模板。大多數C ++模板習語都會在沒有改動的情況下轉移到D,但D增加了一些額外的功能:
D中的模板參數不僅限於類型和原始值,還允許任意編譯時值(如字符串和結構文字),以及任意標識符的別名,包括其他模板或模板實例。
1、模板約束和靜態if語句提供了替代C ++的替換失敗不是錯誤(SFINAE)機制,類似於C ++概念。
2、 is(...)表達式允許推測實例化在編譯時驗證對象的特徵。
3、 auto關鍵字和typeof表達式允許對變量聲明和函數返回值進行類型推斷,這反過來允許“Voldemort類型”(沒有全局名稱的類型)。
D中的模板使用與C ++不同的語法:而在C ++中,模板參數包含在尖括號中(Template <param1, param2>), D使用驚歎號和括號:Template!(param1,param2)。這避免了由於比較運算符的模糊性導致的C ++解析困難。如果只有一個參數,則可以省略括號。
通常,D結合上述特徵以使用基於特徵的通用編程來提供編譯時多態性。例如,輸入範圍定義為滿足isInputRange執行的檢查的任何類型,其定義如下:
template isInputRange(R){    enum bool isInputRange = is(typeof(    (inout int = 0)    {        R r = R.init;     // can define a range object        if (r.empty) {}   // can test for empty        r.popFront();     // can invoke popFront()        auto h = r.front; // can get the front of the range    }));}
然後,只接受輸入範圍的函數可以在模板約束中使用上述模板:
auto fun(Range)(Range range)    if (isInputRange!Range)
    {    // ...}

通用代碼功能

通用代碼Haskell中的通用性

Haskell的類型類機制支持泛型編程。 Haskell中的六個預定義類型類(包括Eq,可以比較相等的類型和Show,其值可以呈現為字符串的類型)具有支持派生實例的特殊屬性 [1]  。 這意味着定義新類型的程序員可以聲明此類型是這些特殊類型類之一的實例,而不提供在聲明類實例時通常需要的類方法的實現。 所有必要的方法都將“派生” - 即根據類型的結構自動構造。 例如,以下一類二叉樹的聲明聲明它是Eq和Show類的一個實例:
data BinTree a = Leaf a | Node (BinTree a) a (BinTree a)      deriving (Eq, Show)
這導致相等函數(==)和字符串表示函數(show)被自動定義為任何類型的表單BinTree T,前提是T本身支持這些操作。
對Eq和Show的派生實例的支持使得它們的方法==並以與參數多態函數在質量上不同的方式顯示泛型:這些“函數”(更準確地説,類型索引的函數族)可以應用於值 各種類型,雖然它們對於每種參數類型的行為都不同,但是需要很少的工作來添加對新類型的支持。 Ralf Hinze(2004)已經表明,通過某些編程技術可以為用户定義的類型類實現類似的效果。 其他研究人員已經在Haskell和Haskell的擴展(下面討論)的上下文中提出了這種和其他類型的通用性的方法。

通用代碼PolyP

PolyP是Haskell的第一個通用編程語言擴展。 在PolyP中,泛型函數稱為polytypic。 該語言引入了一種特殊的構造,其中可以通過對常規數據類型的模式函子的結構的結構歸納來定義這種多型函數。 PolyP中的常規數據類型是Haskell數據類型的子集。 常規數據類型t必須是kind *→*,如果a是定義中的形式類型參數,則對t的所有遞歸調用必須具有t a形式。 這些限制排除了較高級別的數據類型以及嵌套數據類型,其中遞歸調用具有不同的形式。 PolyP中的展平功能在此處作為示例提供:
flatten :: Regular d => d a -> [a]   flatten = cata fl   polytypic fl :: f a [a] -> [a]     case f of       g+h -> either fl fl       g*h -> \(x,y) -> fl x ++ fl y       () -> \x -> []       Par -> \x -> [x]       Rec -> \x -> x       d@g -> concat . flatten . pmap fl       Con t -> \x -> []   cata :: Regular d => (FunctorOf d a b -> b) -> d a -> b

通用代碼通用Haskell

Generic Haskell是荷蘭烏得勒支大學開發的Haskell的另一個擴展。它提供的擴展是:
類型索引值被定義為在各種Haskell類型構造函數(單元,基元類型,總和,產品和用户定義的類型構造函數)上索引的值。此外,我們還可以使用構造函數案例為特定構造函數指定類型索引值的行為,並使用默認情況在另一箇中重用一個泛型定義。
例如,Generic Haskell中的相等函數:
 type Eq {[ * ]} t1 t2 = t1 -> t2 -> Bool   type Eq {[ k -> l ]} t1 t2 = forall u1 u2. Eq {[ k ]} u1 u2 -> Eq {[ l ]} (t1 u1) (t2 u2)   eq {| t :: k |} :: Eq {[ k ]} t t   eq {| Unit |} _ _ = True   eq {| :+: |} eqA eqB (Inl a1) (Inl a2) = eqA a1 a2   eq {| :+: |} eqA eqB (Inr b1) (Inr b2) = eqB b1 b2   eq {| :+: |} eqA eqB _ _ = False   eq {| :*: |} eqA eqB (a1 :*: b1) (a2 :*: b2) = eqA a1 a2 && eqB b1 b2   eq {| Int |} = (==)   eq {| Char |} = (==)   eq {| Bool |} = (==)

通用代碼其他通用代碼

ML系列編程語言通過參數多態和支持仿函數的通用模塊支持泛型編程。 標準ML和OCaml都提供了類似於類模板和Ada通用包的仿函數。 Scheme語法抽象也與泛型有關 - 這些實際上是模板化C ++的超集。
Verilog模塊可以採用一個或多個參數,在模塊實例化時將其實際值分配給該參數。 一個示例是通用寄存器陣列,其中陣列寬度通過參數給出。 這種陣列與通用線矢量相結合,可以使單個模塊實現中的任意位寬的通用緩衝器或存儲器模塊成為可能。
VHDL源自Ada,也具有通用能力。
參考資料