泛型編程

泛型程序設計（英文：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）。

**泛型的定義及目的**
泛型的定義主要有以下兩種：
# 在程序編碼中一些包含類型參數的類型，也就是說泛型的參數只可以代表-{zh-hans:類; zh-hant:類別;}-，不能代表個別-{zh-hans:對象; zh-hant:物件;}-。（這是當今常見的定義）
# 在程序編碼中一些包含參數的-{zh-hans:類; zh-hant:類別;}-。其參數可以代表-{zh-hans:類; zh-hant:類別;}-或-{zh-hans:對象; zh-hant:物件;}-等等。（現在人們大多把這稱作模板）
不論使用哪個定義，泛型的參數在真正使用泛型時都必須作出指明。
一些強類型程序語言支持泛型，其主要目的是加強類型安全及減少-{zh-hans:類; zh-hant:類別;}-轉換的次數，但一些支持泛型的程序語言只能達到部份目的。

**偽代碼例子**
類　例泛類 {
　　值 : T
　　設置值(新值 : T) {
　　　　值 := 新值
　　}
　　獲取值() : T {
　　　　返回　值
　　}
}
例方法1() {
　　例物件 : 例泛類
　　例物件 := 新　例泛類()
　　例物件.設置值(5)
　　輸出整數(例物件.獲取值())
}
例方法2() {
　　例物件 : 例泛類
　　例物件 := 新　例泛類()
　　例物件.設置值(5.5)
　　輸出浮點數(例物件.獲取值())
}
在這例子中，例泛-{A|zh:類;zh-hans:類;zh-hant:類;zh-cn:類;zh-tw:類;zh-hk:類;zh-sg:類;zh-mo:類;}-是一個泛型，而T是一個類型參數。在例泛-{A|zh:類;zh-hans:類;zh-hant:類;zh-cn:類;zh-tw:類;zh-hk:類;zh-sg:類;zh-mo:類;}-中沒指明T的實際類型，只有例方法1()和例方法2()在使用例泛-{A|zh:類;zh-hans:類;zh-hant:類;zh-cn:類;zh-tw:類;zh-hk:類;zh-sg:類;zh-mo:類;}-時才加以指明。
運行這例子的例方法1()將輸出整數5，而運行例方法2()將輸出浮點數5.5。

**一些程序語言的泛型特性**

**.NET 的泛型**
.NET 泛型的參數只可以代表-{zh-hans:類; zh-hant:類別;}-，不能代表個別-{zh-hans:對象; zh-hant:物件;}-。由於 .NET 泛型的類型參數之實際類型在運行時均不會被消除，運行速度會因為類型轉換的次數減少而加快。另外，使用GetType()方法可於程序運行時得知泛型及其類型參數的實際類型，更可以運用反射式編程。
using System;
// 定義一個泛型列表類，T 表示類型參數
public class GenericList
{
private T _items; // 存儲列表items的數組
private int _count; // 列表中items的計數
// 構造函數，初始化列表的容量
public GenericList(int capacity)
{
_items = new Tcapacity;
_count = 0;
}
// 添加item到列表中
public void Add(T item)
{
if (_count = 0 && index  intList = new GenericList(3);
intList.Add(1);
intList.Add(2);
intList.Add(3);
Console.WriteLine(intList.GetItem(1));  // 輸出: 2
// 創建一個存儲字符串的泛型列表
GenericList stringList = new GenericList(2);
stringList.Add("Hello");
stringList.Add("World");
Console.WriteLine(stringList.GetItem(0));  // 輸出: Hello
}
}
在上面的例子中展示了一個簡單的泛型列表類 GenericList，它可以存儲任何類型的數據（由 T 指定）。Program 類中的 Main 方法演示瞭如何使用這個泛型類來存儲和檢索整數和字符串。
.NET 允許對個別泛型的類型參數進行約束，包括以下幾種形式（假設T是泛型的類型參數，C是一般-{zh-hans:類; zh-hant:類別;}-、泛類，或是泛型的類型參數）：
*T是一個-{zh-hans:類; zh-hant:類別;}-。
*T是一個值類型。
*T具有無參數的公有建構方法。
*T實現-{zh-hans:接口; zh-hant:界面;}-I。
*T是C，或繼承自C。

**Java 的泛型**
Java 泛型的參數只可以代表-{zh-hans:類; zh-hant:類別;}-，不能代表個別-{zh-hans:對象; zh-hant:物件;}-。由於Java泛型的類型參數之實際類型在編譯時會被消除，所以無法在運行時得知其類型參數的類型，而且無法直接使用基本值類型作為泛型類型參數。Java編譯程序在編譯泛型時會自動加入類型轉換的編碼，故運行速度不會因為使用泛型而加快。
由於運行時會消除泛型的對象實例類型信息等缺陷經常被人詬病，Java及JVM的開發方面也嘗試解決這個問題，例如：Java通過在生成字節碼時添加類型推導輔助信息，從而可以通過反射接口獲得部分泛型信息；通過改進泛型在JVM的實現，使其支持基本值類型泛型和直接獲得泛型信息等。
Java允許對個別泛型的類型參數進行約束，包括以下兩種形式（假設T是泛型的類型參數，C是一般-{zh-hans:類; zh-hant:類別;}-、泛類，或是泛型的類型參數）：
*T實現接口I。
*T是C，或繼承自C。

**C++的泛型（模板）**
C++ 泛型的參數可以代表-{zh-hans:類; zh-hant:類別;}-或個別-{zh-hans:對象; zh-hant:物件;}-。在一般意義上，C++ 缺乏對泛型的類型參數進行直接約束的手段，但可利用 SFINAE（模板代換失敗非錯誤，指在模板實例化過程中的錯誤僅意味此次代換失敗，並不一定產生編譯錯誤）規則及 C++11 的 static_assert 等實現相似功能。
#include 
class B{
...
};
class D: public B{
...
};
template
void SFINAE(const std::enable_if_t::value, T> &t);
template
void STATIC_ASSERT(const T &t){
static_assert(std::is_pod::value, "Use with POD types only!");
}
如上所示，std::enable_if（std::enable_if_t 是 std::enable_if::type 的縮寫）利用 SFINAE 規則來實現模板類型參數約束的手段之一。其實現方式是若布爾判斷為假，則把類型設為 void，而這將導致 const void & 這種不合法的類型出現，從而禁止這種類型參數的使用。
static_assert 則在布爾判斷失敗時把後面的字符串作為消息內容報告為編譯錯誤。
在編譯時，每個被使用的封閉泛型類型（即是所有泛型參數的實際類型都已被指明的泛型）都會有獨立的編碼產生，編譯程序會在此時確保類型安全性。可是如果泛型要運用其泛型參數的某成員，而該泛型參數又不包含該成員的時候，編譯程序所產生的錯誤信息或會看似與實際問題無關，增加除錯的難度。

**數據源**

**參考文獻**
  ref = harv - dead-url=no - isbn=0-201-63361-2 

**延伸閱讀**
 Gabriel Dos Reis and Jaakko Järvi,  What is Generic Programming?,  LCSD 2005.- Bertrand Meyer. " Genericity vs Inheritance date=20210204215932 ." In OOPSLA (First ACM Conference on Object-Oriented Programming Systems, Languages and Applications), Portland (Oregon), 29 September–2 October 1986, pages 391–405.

**外部連結**
  generic-programming.org date=20201106232314 - Alexander A. Stepanov,  Collected Papers of Alexander A. Stepanov date=20210117034552  (creator of the STL)
C++/D- Walter Bright,  Templates Revisited date=20210207224300 .- David Vandevoorde, Nicolai M Josuttis, C++ Templates: The Complete Guide, 2003 Addison-Wesley. 0-201-73484-2
C#/.NET- Jason Clark, " Introducing Generics in the Microsoft CLR date=20081015140034 ," September 2003, MSDN Magazine, Microsoft.- Jason Clark, " More on Generics in the Microsoft CLR date=20080709093019 ," October 2003, MSDN Magazine, Microsoft.- M. Aamir Maniar,  Generics.Net date=20061021190947 . An open source generics library for C#.
Delphi/Object Pascal- Nick Hodges, " Delphi 2009 Reviewers Guide date=20200220200824 ," October 2008, Embarcadero Developer Network, Embarcadero.- Craig Stuntz, " Delphi 2009 Generics and Type Constraints," October 2008- Dr. Bob, " Delphi 2009 Generics date=20201106232352 "- Free Pascal:  Free Pascal Reference guide Chapter 8: Generics date=20201111213608 , Michaël Van Canneyt, 2007- Delphi for Win32:  Generics with Delphi 2009 Win32 date=20210214152555 , Sébastien DOERAENE, 2008- Delphi for .NET:  Delphi Generics date=20080503224509 , Felix COLIBRI, 2008
Eiffel-  Eiffel ISO/ECMA specification document date=20080616025345 
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 date=20160303230324 - Ralf Hinze, " Generics for the Masses date=20200801003436 ," In Proceedings of the ACM SIGPLAN International Conference on Functional Programming (ICFP), 2004.- Simon Peyton Jones, editor,  The Haskell 98 Language Report date=20201114003023 , 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. 90-393-3765-9-  Generic Haskell: a language for generic programming date=20210411013754 
Java- Gilad Bracha,  Generics in the Java Programming Language date=20120915030303 , 2004.- Maurice Naftalin and Philip Wadler, Java Generics and Collections, 2006, O'Reilly Media, Inc. 0-596-52775-6- Peter Sestoft, Java Precisely, Second Edition, 2005 MIT Press. 0-262-69325-9- Generic Programming In Java, 2004 Sun Microsystems, Inc.- Angelika Langer,  Java Generics FAQs date=20210223033147 
Fanxing