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

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

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

語意

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

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

int x = 10; 
float y;
x = 23;
y = 32.4f;

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

單指定

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

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

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

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

使用單指定的函數式程式設計語言,包括Clojure(針對資料結構,而非變數)、Erlang(相比Haskell,它接受多次指定,如果值相等的話)、F#HaskellLava英語Lava (programming language)OCamlOz(對用資料流變數,而非cell)、Racket(對於一些資料結構如列表,而非符號)、SASLScala(對於變數)、SISALStandard 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[5]

鏈式指定

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

並列指定

一些程式語言,比如APLCommon Lisp[6]Go[7]JavaScript(自從1.7)、LuaMapleoccam 2[8]Perl[9]PHPPython[10]REBOLRuby[11]Windows PowerShell,允許多個變數被並列的指定,語法如下:

a, b := 0, 1

它同時指定0a1b。這經常叫做並列(parallel)指定;它是CPL語言於1963年介入的,當時名字叫做同時(simultaneous)指定[12],有時也叫做(multiple)指定,但這在與(single)指定一起用時會產生混淆,因為它們不是對比的。如果指定的右手側是一個單一變數(比如一個陣列或結構),這個特徵就叫做解包(unpacking)[13]解構(destructuring)指定[14]

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

這個列表將被解包使得指定0a1b。進一步的:

a, b := b, a

對換ab的值。在沒有並列指定的語言中,這必須通過臨時變數來書寫:

var t := a
a := b
b := t

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

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

def f():
    return 1, 2
a, b = f()

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

(a, b) = (b, a);

(string, int) f() => ("foo", 1);
var (a, b) = f();

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

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

指定與等式符號

標記法

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

variable = expression Fortran, PL/I, C (和衍生者比如C++, Java等), Bourne shell, Python, Go (指定預先聲明的變數), R, Windows PowerShell等。
variable := expression ALGOL (和衍生者), Simula, CPL, BCPL, Pascal[16] (和衍生者比如Modula), Mary英語Mary (programming language), PL/M英語PL/M, Ada, Smalltalk, Eiffel[17][18], Oberon, Dylan[19], Seed7英語Seed7, Go (聲明和定義變數的捷徑)[20], Io, AMPL, ML[21], AutoHotkey等。

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

variable << expression Magik英語Magik (programming language)
variable <- expression F#, OCaml, R, S
variable <<- expression R
assign("variable", expression) R
variableexpression APL[22], Smalltalk
variable =: expression J
LET variable = expression BASIC
let variable := expression XQuery英語XQuery
set variable to expression AppleScript
set variable = expression C shell
Set-Variable variable (expression) Windows PowerShell
variable : expression Macsyma英語Macsyma, Maxima, Rebol
var variable expression mIRC手稿語言英語mIRC scripting language
reference-variable :- reference-expression Simula

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

MOVE expression TO variable COBOL
expressionvariable TI-BASIC, Casio BASIC
expression -> variable BETA, R
put expression into variable LiveCode英語LiveCode

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

(setf variable expression) Common Lisp
(set! variable expression) Scheme[23][24][25]
set variable expression Tcl
expression variable ! Forth

另見

註釋

Wikiwand in your browser!

Seamless Wikipedia browsing. On steroids.

Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.

Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.