Parallel_assignment

在程式設計中，**指定敘述**（英語：assignment statement），又譯**指定指述**，會將一個特定的值設定到某個特定的儲存位址去，這個位置被標記成一個特定的變數名稱。換句話說，這個敘述會複製一個值到某個特定變數中。在多數的指令式程式語言中，這種敘述是其中最基礎的結構。

指定敘述的通用表示方法通常是 `x = expr`（這種表示法最早源自 1949 年–1951 年時的 Superplan，因為 1957 年首版的 Fortran 與 C 語言而廣為人知），另一種形式則為 `x := expr`（這種形式最早來自 ALGOL 58，因為 Pascal 而盛行）。在這兩種表示法之外，仍然存在許多其他的形式。

對多數的指令式程式語言來說，指定敘述允許某個特定變數，在其生命週期與作用域之中，可以被指定為不同的值，或是重複被指定值。

## 語意

在指令式編程中，隨著時間改變，不同的值被關聯到某個特定的變數名稱上。變數是數值的容器。可以先指派變數為某個值，在之後再用另一個值來加以取代。在這種模型中，程式的運作，是透過每次成功的指定敘述，來改變其狀態。指令式程式語言，倚靠指定敘述來進行迭代。在最低的層級中，指定敘述是以組合語言指令，如 `MOVE` 或 `STORE` 來實作。

以 C 語言為例，下列的程式碼段落可以作為指定敘述的例子：

在第一行程式碼中，變數 `x` 先被宣告為 int 型別，之後將數值 10 指定給它。在第二行，變數 `y` 被宣告為 float 型別，但沒有指定值。在第三行，變數 `x` 被重新指定為數值 23。在第四行中，變數 `y` 被指定為浮點數值 32.4f。

## 單指定

任何改變現存值的指定（比如 `x := x + 1`），在純函數式語言中都是不允許的。在現今的函式語言程式設計中，指定是被勸阻的，用以支援也叫做「初始化」的單指定。單指定是名字繫結的用例，不同於本文其他部分描述的指定之處在於，它只能做一次，通常是在變數被建立的時候，不允許後續的重新指定。

表達式的求值，如果不改變機器的可察見狀態，並且對相同的輸入產生相同的值，就沒有副作用。指令式指定，在銷毀舊值並使之不可獲得時，在將舊值替代為新值時，就可能介入了副作用；為此在 LISP 和函式語言程式設計中，這被稱為「破壞性」（destructive）指定，類似於「破壞性更新」。

在純函數式語言比如 Haskell 中，單指定是指定的唯一形式，這裡沒有在指令式語言意義上的變數，而是命名的常數值，並具有可能的合成（compoud）本性，即它們的元素 "在需要時" 被逐步的定義。純函式語言程式設計和與之於此共通的資料流程編程，由於值之間相互獨立，可以提供在平行計算上的優勢，它避免了順序的一時一步執行的馮・紐曼瓶頸。

非純函數式語言，同時提供了單指定和真指定（儘管相比指令式程式語言而言真指定典型的較少使用）。例如，在 Scheme 中，單指定（通過 `let`），和真指定（通過 `set!`），二者都可以用於所有變數上，並提供專門的原語（primitive）用於在列表、向量、字串等之內做破壞性更新。在 OCaml 中，只有單指定，通過 `let _name_ = _value_` 語法，被允許用於變數；而破壞性更新，可通過單獨的 `<-` 算符，用於陣列的元素和字串，還可用於已經被編程者顯式聲明為可變（意味著能夠在其初始化聲明之後被變更）的記錄欄位和物件。

使用單指定的函式語言程式設計語言，包括 Clojure（針對資料結構，而非變數）、Erlang（相比 Haskell，它接受多次指定，如果值相等的話）、F#、Haskell、Lava、OCaml、Oz（對用資料流變數，而非 cell）、Racket（對於一些資料結構如列表，而非符號）、SASL、Scala（對於變數）、SISAL、Standard ML。非回溯的 Prolog 代碼可以被看作「明顯的」單指定，這裡明顯的含義為，它的（命名）變數可以顯式的處在未指定狀態，或只能準確的被設定一次。相反的，在 Haskell 中，沒有未指定變數，而所有變數可以看作在建立時就被隱式的設定了它的值（更精確的說是設定了計算物件在「在需要時」產生它的值）。

## 指定語句的回傳值

在一些程式語言中，指定敘述的整個語句可能會傳回某種型別的一個值，而在其它語言中則不會。

在 C 程式語言中指定語句只會單純返回指定值，而允許這樣子的片語 `x = y = a`，其中指定語句 `y = a` 返回值 `a`，然後將值指定到 `x`。在諸如 `while ((ch = getchar()) != EOF) {_…_}` 的語句中，函式的返回值可用於控制迴圈，同時將相同的值指定給變數 `ch`。

在其它程式語言中例如 Scheme，指定語句的返回值是未定義的，而且這些片語無效。

在 Haskell 中沒有變數指定；但類似於指定的操作（如分配給數組的欄位或可變數據結構的欄位）通常以 `unit` 型別為單位進行求值，`unit` 型別以 `()` 表示。這種型別只有一個可能的值，因此不包含任何資訊。它通常是純粹為了副作用而評估的表達型別。

## 指定的變體形式

特定使用模式也非常常見，因此經常有支援它們的特殊語法。這些主要是減少原始碼冗長的語法糖，但也能輔助代碼讀者理解編程者的意圖，並提供給編譯器進行可能的最佳化的線索。

### 增廣指定

所賦予的值依賴於先前的值是很常見的，很多指令式語言，尤其是 C 及其主要衍生者，提供了叫做增廣指定的特殊算符，比如 `*=`，則 `a = 2*a` 可以轉而寫為 `a *= 2`。

### 鏈式指定

語句如 `w = x = y = z` 叫做「鏈式指定」，其中 `z` 的被賦給多個變數 `w`、`x` 和 `y`。鏈式指定經常用來初始化多個變數，比如 `a = b = c = d = f = 0`。

### 並列指定

一些程式語言，比如 APL、Common Lisp、Go、JavaScript（自從 1.7）、Lua、Maple、occam 2、Perl、PHP、Python、REBOL、Ruby、Windows PowerShell，允許多個變數被並列的指定，語法如下：

```
a, b := 0, 1
```

它同時指定 `0` 到 `a` 和 `1` 到 `b`。這經常叫做**並列**（parallel）指定；它是 CPL 語言於 1963 年介入的，當時名字叫做**同時**（simultaneous）指定，有時也叫做**多**（multiple）指定，但這在與**單**（single）指定一起用時會產生混淆，因為它們不是對比的。如果指定的右手側是一個單一變數（比如一個陣列或結構），這個特徵就叫做**解包**（unpacking）或**解構**（destructuring）指定：

```
**var** list := {0, 1}
a, b := list
```

這個列表將被解包使得指定 `0` 至 `a` 和 `1` 至 `b`。進一步的：

```
a, b := b, a
```

對換 `a` 和 `b` 的值。在沒有並列指定的語言中，這必須通過臨時變數來書寫：

```
**var** t := a
a := b
b := t
```

因為 `a := b; b := a` 將把 `a` 和 `b` 二者都指定為 `b` 最初的值。

一些語言，比如 Go 和 Python，將並列指定、元組和自動元組解包結合起來，允許從一個單一函式返回多個值，比如如下 Python 的例子：

而其他語言，比如 C#，要求使用圓括號的顯式元組構造和解構，如下面例子這樣：

這提供了從一個函式返回多個值要使用輸出參數的一種替代方式。這最早見於 CLU 語言（1974 年），而 CLU 推動了一般的並列指定變得流行。

在 C 和 C++ 中，逗號運算子，在允許多個指定出現在一個單一語句上類似於並列指定，寫 `a = 1, b = 2` 替代 `a, b = 1, 2`。這主要用在 for 迴圈中，在其他語言比如 Go 中，被替代為並列指定。但是上述 C++ 代碼不確保完全的同時性，因為代碼 `a = b, b = a+1` 的右側項是在左側項之後運算的。在語言如 Python 中，`a, b = b, a+1` 將並行的指定兩個變數，使用最初的 `a` 的值來計算新 `b` 的值.

## 指定與等式符號

## 標記法

複製分配的兩個最常見的表示形式是等號（`=`）和冒號等於（`:=`）。這兩種形式都可以在語義上表示賦值語句或設定運算子（它也具有值），這取決於語言用法。

　
:

其他可能性包括左箭頭或關鍵字，但還有其他更罕見的變體：

　
:

數學虛擬碼分配通常用左箭頭表示。有些平台將表達式放在左側，變數放在右側：

　
:

一些面向運算式的語言比如 Lisp 和 Tcl，對所有語句（包括賦值）統一使用前綴（或後綴）語法。

　
:

## 另見

* 設定運算子
* 算符 (編程)
* 名字繫結
* 合一
* 不可變物件
* 常數 (電腦編程)

## 註釋