程序設計中,指定敘述(英語: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

另見

编辑

註釋

编辑
  1. ^ 1.0 1.1 1.2 Crossing borders: Explore functional programming with Haskell 互联网档案馆存檔,存档日期November 19, 2010,., by Bruce Tate
  2. ^ Mitchell, John C. Concepts in programming languages. Cambridge University Press. 2003: 23 [3 January 2011]. ISBN 978-0-521-78098-8. 
  3. ^ Imperative Programming Languages (IPL) (PDF). gwu.edu. [20 April 2018]. (原始内容存档 (PDF)于2021-01-18). 
  4. ^ John C. Mitchell. Concepts in programming languages. Cambridge University Press. 2003: 81–82 [3 January 2011]. ISBN 978-0-521-78098-8. 
  5. ^ Ruediger-Marcus Flaig. Bioinformatics programming in Python: a practical course for beginners. Wiley-VCH. 2008: 98–99 [25 December 2010]. ISBN 978-3-527-32094-3. (原始内容存档于2017-04-19). 
  6. ^ CLHS: Macro SETF, PSETF. Common Lisp Hyperspec. LispWorks. [23 April 2019]. (原始内容存档于2020-11-30). 
  7. ^ The Go Programming Language Specification: Assignments页面存档备份,存于互联网档案馆
  8. ^ INMOS Limited (编). Occam 2 Reference Manual. New Jersey: Prentice Hall. 1988. ISBN 0-13-629312-3. 
  9. ^ Wall, Larry; Christiansen, Tom; Schwartz, Randal C. Perl Programming Language 2. Cambridge: O´Reilly. 1996. ISBN 1-56592-149-6. 
  10. ^ Lutz, Mark. Python Programming Language 2. Sebastopol: O´Reilly. 2001. ISBN 0-596-00085-5. 
  11. ^ Thomas, David; Hunt, Andrew. Programming Ruby: The Pragmatic Programmer's Guide. Upper Saddle River: Addison Wesley. 2001. ISBN 0-201-71089-7. 
  12. ^ D.W. Barron et al., "The main features of CPL", Computer Journal 6:2:140 (1963). full text (subscription) Archive.today存檔,存档日期2012-07-07
  13. ^ PEP 3132 -- Extended Iterable Unpacking. legacy.python.org. [20 April 2018]. (原始内容存档于2016-05-13). 
  14. ^ Destructuring assignment. MDN Web Docs. [20 April 2018]. (原始内容存档于2021-02-10). 
  15. ^ Effective Go页面存档备份,存于互联网档案馆): for页面存档备份,存于互联网档案馆), "Finally, Go has no comma operator and ++ and -- are statements not expressions. Thus if you want to run multiple variables in a for you should use parallel assignment (although that precludes ++ and --)."
  16. ^ Moore, Lawrie. Foundations of Programming with Pascal. New York: John Wiley & Sons. 1980. ISBN 0-470-26939-1. 
  17. ^ Meyer, Bertrand. Eiffel the Language. Hemel Hempstead: Prentice Hall International(UK). 1992. ISBN 0-13-247925-7. 
  18. ^ Wiener, Richard. An Object-Oriented Introduction to Computer Science Using Eiffel. Upper Saddle River, New Jersey: Prentice Hall. 1996. ISBN 0-13-183872-5. 
  19. ^ Feinberg, Neal; Keene, Sonya E.; Mathews, Robert O.; Withington, P. Tucker. Dylan Programming. Massachusetts: Addison Wesley. 1997. ISBN 0-201-47976-1. 
  20. ^ The Go Programming Language Specification - The Go Programming Language. golang.org. [20 April 2018]. (原始内容存档于2021-03-18). 
  21. ^ Ullman, Jeffrey D. Elements of ML Programming: ML97 Edition. Englewood Cliffs, New Jersey: Prentice Hall. 1998. ISBN 0-13-790387-1. 
  22. ^ Iverson, Kenneth E. A Programming Language. John Wiley and Sons. 1962. ISBN 0-471-43014-5. (原始内容存档于2009年6月4日). 
  23. ^ Dybvig, R. Kent. The Scheme Programming Language: ANSI Scheme. New Jersey: Prentice Hall. 1996. ISBN 0-13-454646-6. 
  24. ^ Smith, Jerry D. Introduction to Scheme. New Jersey: Prentice Hall. 1988. ISBN 0-13-496712-7. 
  25. ^ Abelson, Harold; Sussman, Gerald Jay; Sussman, Julie. Structure and Interpretation of Computer Programs. New Jersey: McGraw-Hill. 1996. ISBN 0-07-000484-6. 

📚 Artikel Terkait di Wikipedia

Standard ML

1145/582153.582176. (原始内容 (PDF)存档于2022-03-22).  Damas, Luis. Type Assignment in Programming Languages (PDF) (PhD论文). University of Edinburgh. 1985 [2021-09-02]

B語言

function scope), not "automatic typing" as in C++11. */ if (a = n / b) /* assignment, not test for equality */ printn(a, b); /* recursive */ putchar(n % b

SAC语言

SAC(Single Assignment C)是一门严格的纯函数式编程语言,以满足数值计算领域的需求为主要目的。怎样实现对多维数组的高效计算是SAC的核心部分。效率在程序设计领域可以有两方面的理解。一方面是提供高级的数组运算操作,以加快开发程序,另一方面是在某种模式下优化编译程序,以减少其所需的运

Python

syntax. [2019-11-21]. (原始内容存档于2019-01-05).  What’s New in Python 3.8 - Assignment expressions. [2023-03-08]. (原始内容存档于2021-06-01).  Paul Krill, Guido Van

R语言

recommend the consistent use of the preferred assignment operator ‘<-’ (rather than ‘=’) for assignment.  Google's R Style Guide. [2018-09-11]. (原始内容存档于2019-01-11)

運籌學

Method for the Assignment Problem," Naval Research Logistics Quarterly, 1–2, 1955, 83–97 H. W. Kuhn, A. W. Tucker, "Nonlinear Programming," pp. 481–492

競爭危害

by G.M. Karam and R.J.A. Buhr Paper "Algorithms for the Optimal State Assignment of Asynchronous State Machines (页面存档备份,存于互联网档案馆)" by Robert M. Fuhrer

設定運算子

在C++程式語言裡,設定運算子(英文:assignment operator)是用等號 = 符號。就像其他的C++運算子一樣,它可以作為多載。 複製設定運算子是一個特別的設定運算子,通常是用來把已存在的物件指定給其他相同類別的物件。它是一個特別的成員函式,如果程式設計師沒有定義這個成員函式,那麼編譯