泛型编程

**泛型程式設計**（英文：generic programming）是程式設計語言的一種風格或範式。泛型允許程式設計師在強型別程式設計語言中編寫代碼時使用一些以後才指定的類型，在實例化時作為參數指明這些類型。各種程式語言和其編譯器、執行環境對泛型的支援均不同。Ada、Delphi、Eiffel、Java、C#、F#、Swift 和 Visual Basic .NET 稱之為泛型（generics）；ML、Scala 和 Haskell 稱之為參數多型（parametric polymorphism）；C++ 和 D 稱之為模板。具有廣泛影響的 1994 年版的《Design Patterns》一書稱之為參數化類型（parameterized type）。

## 泛型的定義及目的

泛型的定義主要有以下兩種：

1. 在程式編碼中一些包含**類型參數**的類型，也就是說泛型的參數只可以代表類別，不能代表個別物件。（這是當今常見的定義）
2. 在程式編碼中一些包含參數的類別。其參數可以代表類別或物件等等。（現在人們大多把這稱作模板）

不論使用哪個定義，泛型的參數在真正使用泛型時都必須作出指明。

一些強類型程式語言支援泛型，其主要目的是加強類型安全及減少類別轉換的次數，但一些支援泛型的程式語言只能達到部份目的。

## 虛擬碼例子

在這例子中，`例泛類` 是一個泛型，而 `T` 是一個類型參數。在 `例泛類` 中沒指明 `T` 的實際類型，只有 `例方法1()` 和 `例方法2()` 在使用 `例泛類` 時才加以指明。

運行這例子的 `例方法1()` 將輸出整數 5，而運行 `例方法2()` 將輸出浮點數 5.5。

## 一些程式語言的泛型特性

### .NET 的泛型

.NET 泛型的參數只可以代表类别，不能代表個別物件。由於 .NET 泛型的類型參數之實際類型在執行時均不會被消除，執行速度會因為類型轉換的次數減少而加快。另外，使用 `GetType()` 方法可於程式執行時得知泛型及其類型參數的實際類型，更可以運用反射式編程。

.NET 允許對個別泛型的類型參數進行約束，包括以下幾種形式（假設 `T` 是泛型的類型參數，`C` 是一般類別、泛類，或是泛型的類型參數）：

* `T` 是一個類別。
* `T` 是一個值類型。
* `T` 具有無參數的公有建構方法。
* `T` 實現界面 `I`。
* `T` 是 `C`，或繼承自 `C`。

### Java 的泛型

Java 泛型的參數只可以代表类别，不能代表個別物件。由於 Java 泛型的類型參數之實際類型在編譯時會被消除，所以無法在執行時得知其類型參數的類型，而且無法直接使用基本值類型作為泛型類型參數。Java 編譯程式在編譯泛型時會自動加入類型轉換的編碼，故執行速度不會因為使用泛型而加快。

由於執行時會消除泛型的物件實例類型資訊等缺陷經常被人詬病，Java 及 JVM 的開發方面也嘗試解決這個問題，例如：Java 通過在生成位元組碼時添加類型推導輔助資訊，從而可以通過反射介面獲得部分泛型資訊；通過改進泛型在 JVM 的實現，使其支援基本值類型泛型和直接獲得泛型資訊等。

Java 允許對個別泛型的類型參數進行約束，包括以下兩種形式（假設 `T` 是泛型的類型參數，`C` 是一般類別、泛類，或是泛型的類型參數）：

* `T` 實現介面 `I`。
* `T` 是 `C`，或繼承自 `C`。

### C++ 的泛型（模板）

C++ 泛型的參數可以代表类别或個別物件。在一般意義上，C++ 缺乏對泛型的類型參數進行直接約束的手段，但可利用 SFINAE（模板代換失敗非錯誤，指在模板實例化過程中的錯誤僅意味此次代換失敗，並不一定產生編譯錯誤）規則及 C++11 的 static\_assert 等實現相似功能。

如上所示，std::enable\_if（std::enable\_if\_t<boolean, Type> 是 std::enable\_if<boolean, Type>::type 的縮寫）利用 SFINAE 規則來實現模板類型參數約束的手段之一。其實現方式是若布林判斷為假，則把類型設為 void，而這將導致 const void & 這種不合法的類型出現，從而禁止這種類型參數的使用。

static\_assert 則在布林判斷失敗時把後面的字串作為訊息內容報告為編譯錯誤。

在編譯時，每個被使用的**封閉泛型類型**（即是所有泛型參數的實際類型都已被指明的泛型）都會有獨立的編碼產生，編譯程式會在此時確保類型安全性。可是如果泛型要運用其泛型參數的某成員，而該泛型參數又不包含該成員的時候，編譯程式所產生的錯誤資訊或會看似與實際問題無關，增加除錯的難度。

## 資料來源

## 參考文獻

## 延伸閱讀

## 外部連結

* generic-programming.org （頁面存檔備份，存於網際網路檔案館）
* Alexander A. Stepanov, Collected Papers of Alexander A. Stepanov （頁面存檔備份，存於網際網路檔案館） (creator of the STL)

**C++/D**

* Walter Bright, _Templates Revisited （頁面存檔備份，存於網際網路檔案館）._
* David Vandevoorde, Nicolai M Josuttis, _C++ Templates: The Complete Guide_, 2003 Addison-Wesley. ISBN 0-201-73484-2

**C#/.NET**

* Jason Clark, "Introducing Generics in the Microsoft CLR （頁面存檔備份，存於網際網路檔案館）," September 2003, _MSDN Magazine_, Microsoft.
* Jason Clark, "More on Generics in the Microsoft CLR （頁面存檔備份，存於網際網路檔案館）," October 2003, _MSDN Magazine_, Microsoft.
* M. Aamir Maniar, Generics.Net （頁面存檔備份，存於網際網路檔案館）. An open source generics library for C#.

**Delphi/Object Pascal**

* Nick Hodges, "Delphi 2009 Reviewers Guide （頁面存檔備份，存於網際網路檔案館）," October 2008, _Embarcadero Developer Network_, Embarcadero.
* Craig Stuntz, "Delphi 2009 Generics and Type Constraints," October 2008
* Dr. Bob, "Delphi 2009 Generics （頁面存檔備份，存於網際網路檔案館）"
* Free Pascal: Free Pascal Reference guide Chapter 8: Generics （頁面存檔備份，存於網際網路檔案館）, Michaël Van Canneyt, 2007
* Delphi for Win32: Generics with Delphi 2009 Win32 （頁面存檔備份，存於網際網路檔案館）, Sébastien DOERAENE, 2008
* Delphi for .NET: Delphi Generics （頁面存檔備份，存於網際網路檔案館）, Felix COLIBRI, 2008

**Eiffel**

* Eiffel ISO/ECMA specification document （頁面存檔備份，存於網際網路檔案館）

**Haskell**

* Johan Jeuring, Sean Leather, José Pedro Magalhães, and Alexey Rodriguez Yakushev. _Libraries for Generic Programming in Haskell_. Utrecht University.
* Dæv Clarke, Johan Jeuring and Andres Löh, The Generic Haskell user's guide （頁面存檔備份，存於網際網路檔案館）
* Ralf Hinze, "Generics for the Masses （頁面存檔備份，存於網際網路檔案館）," In _Proceedings of the ACM SIGPLAN International Conference on Functional Programming (ICFP),_ 2004.
* Simon Peyton Jones, editor, _The Haskell 98 Language Report （頁面存檔備份，存於網際網路檔案館）,_ Revised 2002.
* Ralf Lämmel and Simon Peyton Jones, "Scrap Your Boilerplate: A Practical Design Pattern for Generic Programming," In _Proceedings of the ACM SIGPLAN International Workshop on Types in Language Design and Implementation (TLDI'03),_ 2003. (Also see the website devoted to this research)
* Andres Löh, _Exploring Generic Haskell,_ Ph.D. thesis, 2004 Utrecht University. ISBN 90-393-3765-9
* Generic Haskell: a language for generic programming （頁面存檔備份，存於網際網路檔案館）

**Java**

* Gilad Bracha, _Generics in the Java Programming Language （頁面存檔備份，存於網際網路檔案館）,_ 2004.
* Maurice Naftalin and Philip Wadler, _Java Generics and Collections,_ 2006, O'Reilly Media, Inc. ISBN 0-596-52775-6
* Peter Sestoft, _Java Precisely, Second Edition,_ 2005 MIT Press. ISBN 0-262-69325-9
* Java SE 7, 2004 Sun Microsystems, Inc.
* Angelika Langer, Java Generics FAQs （頁面存檔備份，存於網際網路檔案館）