參數 (程式設計)

範例

以下使用C語言編寫的程式定義了一個名為SalesTax的函式，並具有一個名為price的參數。price的類型是double，也就是雙精度浮點數。該函式的返回類型也是double。
double SalesTax( double price ){
  return 0.05 * price;}
定義函式後，可以按以下方式調用它：
SalesTax(10.00);
範例中使用了引數10.00調用了該函式，此時將為price分配一個值10.00，然後該函式開始計算其結果。產生結果的步驟在下面指定，並用並用{}括起來。0.05 * price表示要做的第一件事是將價格乘以0.05，即得出0.50。return表示函式將產生的結果0.05 * price返回。因此，最終結果（忽略將小數部分表示為二進制時可能遇到的捨入誤差）為0.50。

參數和引數

在不同的程式語言中，術語參數和引數可能會具有不同的含義。有時它們可以互換使用，並且以上下文區分含義。術語參數（也稱為形式參數（形參，formal parameter））通常用來指該變數作為在函式定義中變數的內容。而引數（也稱為實際參數（實參，actual parameter））是指在函式調用中提供的實際輸入。例如，如果將一個函式定義為def f(x): ...，x則為參數。若定義有a = ...; f(a)來呼叫函式，那麼這裡的a就是引數。參數是一個（未綁定實際值的）變數，而引數可以是一個值或變數，或者是涉及值和變數的更複雜的表達式。在由值呼叫的情況下，所傳遞給函式是自變數的值。例如f(2)和a = 2; f(a)對函式的呼叫是相同的，在以變數作為參數通過參照調用時，若函式調用的語法可以保持不變，則傳遞的是對該變數的參照。具體[[求值策略#傳值呼叫（Call by value）|按值傳遞]]或者是[[求值策略#傳參照呼叫（Call by reference）|按參照傳遞]]的細節規範則由函式的聲明以及定義中進行。
一般而言，參數出現在過程定義中，引數則出現在過程調用中。在函式f(x) = x*x的定義中，變數x是參數。在函式f(2)調用中，值2是該函式的引數。簡單而不太準確的概擴來說參數是類型，而引數是實作。 
參數是過程的原生屬性，包含在其定義中。例如，在許多語言中，將兩個提供的整數加在一起併計算總和的過程將需要兩個參數，每個整數一個。通常，可以使用任意數量的參數或完全不使用參數來定義過程。如果過程具有參數，則其定義中指定參數的部分稱為其參數列表（parameter list）。 
相反，引數是調用過程時提供給過程的表達式，其通常是一個與參數之一匹配的表達式。與參數（它們構成過程定義的不變部分）不同，自變數在調用之間可能有所不同。每次調用過程時，過程調用中指定引數的部分稱為引數列表（argument list）。 
儘管參數通常也被混稱為引數，但是在運行時調用次常式時，有時會將引數視為分配給參數變數的實際值或參照。在討論正在調用次常式的程式碼時，傳遞給次常式的任何值或參照都是引數。 

在討論次常式定義中的程式碼時，次常式的參數列表中的變數是參數，而運行時參數的值則會是引數。例如，在C語言中，處理執行緒時通常會傳入void *類型的參數並將其強制轉換為預期的類型： 
void ThreadFunction( void* pThreadArgument ){
  //將第一個參數命名為pThreadArgument而不是pThreadParameter是正確的。
  //在運行時，我們使用的值是一個引數。
  //如上所述，在討論子例程定義時保留術語參數。}
為了更好地理解它們之間的區別，請考慮以下用C語言編寫的函式： 
int Sum( int addend1, int addend2 ){
  return addend1 + addend2;}
函式Sum具有兩個參數，分別名為addend1和addend2，這個函式將傳遞給參數的值相加，然後將結果返回給次常式的調用方（使用C語言編譯器自動提供的技術）。 
調用Sum函式的程式碼可能如下所示： 
int value1 = 40;int value2 = 2;int sum_value = Sum(value1, value2);
變數value1和value2用值初始化。在這種情況下，value1和value2都是sum函式的引數。 
在運行時，分配給這些變數的值作為參數傳遞給函式Sum。在Sum函式中，將會對參數addend1和addend2進行求值，分別得出參數40和2。將添加參數的值，並將結果返回給調用方，在此將其分配給變數sum_value。 
由於參數和引數之間的差異，有可能向過程提供不合適的引數，也可能提供過多或過少的引數，要麼一個或多個引數可能是錯誤的類型，或者是以錯誤的順序提供了引數。這些情況中的任何一種都會導致參數列表和引數列表之間不匹配，並且該過程通常會返回意外的答案或生成執行期錯誤。

資料類型

在強類型程式語言中，必須在過程聲明中指定每個參數的類型。使用類型推斷的語言會嘗試從函式的主體和用法中自動推斷類型。動態類型的程式語言則會將類型解析推遲到運行時。弱類型語言幾乎沒有類型解析，甚至依靠程式員來確保正確性。
一些語言使用特殊的關鍵字（例如void）來指示該次常式沒有參數。在形式類型理論中，此類函式採用空參數列表（其類型不是void，而是unit）。

引數傳遞

將參數分配給參數的確切機制稱為參數傳遞（argument passing），該機製取決於可以使用關鍵字來指定的參數求值策略（通常為按值傳遞）。

默認引數

某些程式語言（例如Ada，C++，Clojure，Common Lisp，Fortran 90，Python，Ruby，Tcl和Windows PowerShell）允許在次常式的聲明中顯式或隱式給出默認引數。這允許調用者在調用次常式時忽略該參數。如果顯式給出了默認引數，則如果調用者未提供該值，則使用該值。如果默認引數是隱式的（有時通過使用諸如Optional之類的關鍵字），則該語言將提供一個通常值（例如null、Empty、0、空字串等）。

PowerShell範例：
 function doc($g = 1.21) {
   "$g gigawatts? $g gigawatts? Great Scott!"
 }
PS  > doc1.21 gigawatts? 1.21 gigawatts? Great Scott!PS  > doc 8888 gigawatts? 88 gigawatts? Great Scott!
默認引數可以看作是可變長度引數列表的一種特殊情況。

可變長度參數列表

某些語言允許將次常式定義為接受可變數量的引數。對於此類語言，次常式必須遍歷參數列表。

PowerShell範例：
 function marty {
   $args | foreach { "back to the year $_" }
 }
PS  > marty 1985back to the year 1985PS  > marty 2015 1985 1955back to the year 2015back to the year 1985back to the year 1955

命名參數

某些程式語言（例如Ada和Windows PowerShell）許次常式具有命名參數。這使調用程式碼更具自記錄性。它還為調用者提供了更大的靈活性，通常允許更改參數的順序，或者根據需要省略參數。

PowerShell範例：
 function jennifer($adjectiveYoung, $adjectiveOld) {
   "Young Jennifer: I'm $adjectiveYoung!"
   "Old Jennifer: I'm $adjectiveOld!"
 }
PS  > jennifer 'fresh' 'experienced'Young Jennifer: I'm fresh!Old Jennifer: I'm experienced!PS  > jennifer -adjectiveOld 'experienced' -adjectiveYoung 'fresh'Young Jennifer: I'm fresh!Old Jennifer: I'm experienced!

函式語言中的多個參數

在lambda演算中，每個函式只有一個參數。通常認為具有多個參數的函式在lambda演算中表示為具有第一個引數的函式，並返回具有其餘引數的函式。這種轉換也被稱為柯里化（Currying）。一些程式語言（例如ML和Haskell）遵循此方案。在這些語言中，每個函式都只有一個參數，看起來像多個參數的函式的定義，實際上是返回一個函式的函式的定義的語法糖等。在這些語言以及lambda演算中的函式應用是左關聯的，因此，這種操作看起來會像是將函式應用於多個引數的函式先將函式應用於第一個引數，然後將結果函式應用於第二個自變數，並依此類推。

輸出參數

輸出參數，也稱為出參或返回參數，是一種用於輸出而不是更通常的使用用於輸入的參數。在某些語言中，尤其是C和C ++，輸出參數是一種習慣用法，而其他語言則內置了對輸出參數的支援。內置支援輸出參數的語言包括Ada、Fortran、SQL的各種拓展程式（例如：PL/SQL和Transact-SQL）、Ｃ#和.Net Framework、Swift以及手稿語言TScript。
更準確地說，參數模式或參數共有三種類型：輸入參數（入參）、輸出參數（出參）、輸入輸出參數（出入參），這些參數往往使用in、out、inout來進行表示。輸入引數輸入引數（針對輸入參數的引數）必須是一個值，例如已經被初始化了的變數或常值，而且不能重新定義獲分配它。輸出引數必須是可分配變數，但不必初始化而且任何現有值均不可存取輸入值，執行函式後必須分配一個值。蘇入輸出引數必須是已初始化了的可分配變數，並且可以選擇給其分配一個值。確切的要求和執行情況因語言而異，例如在Ada 83中，即使分配後也只能分配輸出參數（在Ada 95中刪除了該參數，以消除對輔助累加器變數的需要）。這有些類似於值的概念，也就是左值（l-value，具有值）、右值（r-value，可分配）以及左右值（l-value/r-value，具有值且可分配），不過這些術語在C語言中有特殊含意。
在某些情況下，只有輸入和輸入輸出是有區別的，而輸出則被視為輸入/輸出的特定用途，而在其他情況下，僅支援輸入和輸出（但不支援輸入輸出）。默認模式因語言而異：在Fortran 90中，默認輸入/輸出，在C＃和SQL擴展中，默認輸入/輸出，在TScript中，每個參數都明確指定為輸入或輸出。

從語法上講，參數模式通常在函式聲明（例如在C＃中：void f(out int x)）中用關鍵字表示。通常，輸出參數通常放在參數列表的末尾以清楚地區分它們。TScript使用另一種方​​法，其中在函式聲明中列出了輸入參數，然後列出了輸出參數，並用冒號（:）分隔，並且函式本身沒有返回類型，如在此函式中一樣，該函式用於計算文字的大小分段：
 TextExtent(WString text, Font font : Integer width, Integer height)
參數模式是指稱語義的一種形式，其表明了程式設計師的意圖並允許編譯器捕獲錯誤來應用最佳化，它們不​​一定暗示操作語義（參數傳遞的實際發生方式）。值得注意的是，雖然輸入參數可以通過值調用實現，而輸出和輸入輸出參數可以通過參照調用實現，這是在沒有內置支援的情況下以語言實現這些模式的直接方法，但也並非總是如此實施。《Ada '83基本原理（英語：Ada '83 Rationale）》中詳細討論了這種區別，其中強調了參數模式是從中實際實現的參數傳遞機制（通過參照或通過複製）抽像出來的。例如，在C＃中，按值傳遞輸入參數（默認，無關鍵字），而按參照傳遞輸出和輸入/輸出參數（out和ref），而在PL / SQL中傳遞輸入參數（IN）通過參照，默認情況下通過值傳遞輸出和輸入/輸出參數（OUT和IN OUT），並將結果復制回去，但是可以使用NOCOPY編譯器提示通過參照傳遞。
與輸出參數在語法上相似的構造是將返回值分配給與函式名稱相同的變數。 可以在Pascal和Fortran 66和Fortran 77中發現，此處使用Pascal範例：
function f(x, y: integer): integer;begin
    f := x + y;end;
這在語義上是不同的，因為在調用時僅對函式進行求值–不會從調用範圍傳遞變數來儲存輸出。

使用

輸出參數的主要用途是從一個函式返回多個值，而輸入/輸出參數的用途是使用參數傳遞（而不是像全域變數那樣在共用環境中）來修改狀態。 返回多個值的一個重要用途是解決返回值和錯誤狀態的半謂詞問題。

例如，要從C函式中返回兩個變數，可以寫：
int widthint height;F(x, &width, &height);
其中x是輸入參數， width和height是輸出參數。
C和相關語言的一個常見用例是異常處理 ，其中函式將返回值放在輸出變數中，並返回一個布爾值，該布爾值對應於函式是否成功。 一個典型的例子是.NET中的TryParse方法，尤其是C＃，它將字串解析為整數，成功則返回true ，失敗則返回false 。 其具有以下形式：
public static bool TryParse(string s, out int result)
可以這樣使用：
int result;if (!Int32.TryParse(s, result)) {
    // exception handling}
類似的考慮適用於返回幾種可能類型之一的值，其中返回值可以指定類型，然後將值儲存在幾種輸出變數之一中。

缺點

在現代編程中，通常不鼓勵使用輸出參數，因為它們笨拙、令人困惑且級別太低，普通的返回值相當容易理解和使用。值得注意的是，輸出參數涉及具有副作用（修改輸出參數）的函式，並且在語義上與參照相似，比純函式和值更容易混淆，並且輸出參數與輸入/輸出參數之間的區別可能微妙。 此外，由於在通常的編程樣式中，大多數參數只是輸入參數，因此輸出參數和輸入輸出參數是異常的，從而容易引起誤解。

輸出和輸入輸出參數會阻止函式組合，因為輸出儲存在變數中，而不是表達式的值中。 因此，必須首先聲明一個變數，然後函式鏈的每一步都必須是一個單獨的語句。 例如，在C ++中，以下函式組成：
Object obj = G(y, F(x));
當寫有輸出和輸入輸出參數時，可以寫為（對於F是輸出參數，對於G是輸入/輸出參數）：
Object obj;F(x, &obj);G(y, &obj);
在具有單個輸出或輸入/輸出參數且沒有返回值的函式的特殊情況下，如果該函式還返回輸出或輸入輸出參數（或在C / C ++中是其位址），則可以構成函式，在這種情況下，以上內容將變為：
Object obj;G(y, F(x, &obj));

替代方式

輸出參數的用例有多種選擇。

為了從一個函式返回多個值，一種替代方法是返回一個元組 。 從語法上講，如果可以使用自動序列拆包和並行賦值 （例如在Go或Python中），這會更清楚：
def f():
    return 1, 2a, b = f()
為了返回幾種類型之一的值，可以使用標籤聯合 。最常見的情況是可空類型 （ 可選型別 ），其中返回值可以為null以指示失敗。對於異常處理，可以返回可為null的類型，也可以引發異常。 例如，在Python中，可能有以下兩種情況之一：
result = Parse(s)if result is None:
    # exception handling
或者，更慣用的方法：
try:
    result = Parse(s)except ParseError:
    # exception handling
不需要局部變數並在使用輸出變數時復制返回值的微最佳化也可以通過足夠複雜的編譯器應用於常規函式和返回值。
使用C和相關語言輸出參數的通常替代方法是返回包含所有返回值的單個資料結構。 例如，給定一個封裝寬度和高度的結構，可以這樣寫：
WidthHeight width_and_height = F(x);
在面向物件的語言中，通常不使用輸入輸出參數，而是通過[[求值策略#傳共用物件呼叫（Call by sharing）|傳共用調用]] ，將參照傳遞給物件然後對物件進行突變來使用調用 ，而不更改變數所參照的物件。