變量 (程序設計)

本頁使用了標題或全文手工轉換
維基百科,自由的百科全書

程序設計中,變數(英語:Variablescalar)是指一個抽象的儲存位址,它含有了被稱為一個的某種已知或未知的資訊,並且配對了關聯的符號名稱。通常使用變數名稱參照儲存值;將名稱和內容分開能讓被使用的名稱獨立於所表示的精確訊息之外。電腦原始碼中的識別字能在執行期間綁紮一個,且該變數的值可能在程式執行期間改變。 程序設計中的變數不一定能直接對應到數學中所謂的變數之概念。在程序設計中,變數的值不一定要為方程數學公式之一部分。程序設計中的變數可使用在一段可重復的程序:在一處賦值,然後使用於另一處,接著在一次賦值,且以相同方式再使用一次(見迭代)。程序設計中的變數通常會給定一個較長的名稱,以描述其用途;數學中的變數通常較為簡潔,只給定一、兩個字母,以方便抄寫及操作。

一個變數的儲存位址可以被不同的識別字所參照,這種情況稱之為別名。使用其中一個識別字為變數賦值,將會改變透過另一個識別字存取的值。

編譯器必須將代表變數的名稱替代成該數據所在的實際位址。變數的名稱、類型及位址通常會維持固定,但該位址所儲存之數據於程式執行期間則可能會改變。

用標識符引用變量

用標識符引用變量能對變量進行訪問,從而讀取變量的值,改變變量的值,或者改變變量的屬性(如訪問權限、狀態鎖定等)。

例如,一個變量用標識符total_count來引用,設定這個變量的值為1981。如果該變量同時也用標識符x 來引用,通過x將變量值改變為2010,那麼讀取total_count的值就是2010而不是1981。

如果某種編程語言只允許同一個變量用一個標識符引用,那麼「該變量的名字」就是有意義的,否則我們稱之為「該變量的名字之一」。例如,在前面的那個例子當中,total_count是這個變量的名字之一,而x是這個變量的另外一個名字。

對變量的操作

指令式編程語言中,變量的值通常能夠隨時訪問或重新賦值。但在邏輯編程語言中,根據參數透明的需求,變量被綁定到表達式並且在它的整個生命周期中保持同一個值。在指令式編程語言中,同樣的行為用常量來表達,它和通常的變量存在反差。

根據編程語言的類型系統的不同,變量可能只存儲一種特定的數據類型(如整型字符串型)。而另外一種情況,變量的數據類型能根據當前賦值而改變,允許單個變量存儲該編程語言支持的任何數據類型。

命名規範

數學當中的量不同,程序設計所用的變量和常量通常都採用多字符的名字,如count或者size。而單個字符的名字一般僅用於輔助性的變量,如ijk常作為數組索引的變量。

一些命名規範是作為語法在語言層面強制執行的。在大多數語言當中,變量名不能以數字開頭,不能包含空格符。而標點符號是否允許存在在變量名當中就要視具體語言而定了。很多語言僅僅允許下劃線_存在在變量名當中,而禁止其他所有的標點符號;而有些編程語言,特殊字符作為前綴或後綴添加在變量標識符當中來表明變量的類型。變量名的大小寫敏感性也要視具體語言而定。大多數現代語言是大小寫敏感的,一些較老的語言則不敏感。一些語言保留特定形式的變量名用來內部使用,在很多語言中,以兩根下劃線開頭__的變量名常充當這種角色。

在語言語法基本的限制以外,進一步的命名風格規範也很有必要。在機器碼層面,是不會使用變量名的,所以計算機並不關心是否採用了準確的名字。正因為如此,變量名完全是作為程序員的工具而存在,藉助這個工具程序員能更容易的編寫和理解程序。程序員通常創建編碼規範,並且堅持這些規範,幫助對變量命名甚至提供精確的命名規劃。較短的名字便於輸入,但是描述能力較差;較長的名字使程序更容易讀懂,變量的意圖更容易理解。儘管如此,冗長的變量名也可能會導致更難理解的代碼。

在源代碼中

源代碼中,變量名是將變量和內存地址綁定的一種方式。變量值以數據對象的形式存儲在相應的地址內,這樣該數據對象就能通過變量的名字進行訪問和修改了。

在電子表格中

電子試算表中,一個單元格可能包含參考其他單元格的公式。這種被參考的單元格就是一種形式的變量,它的值就是被參考的單元格的值。

作用域和生存周期

變量的作用域表示變量在原程序的文本中能被使用的範圍。變量的生存周期表示變量在程序運行過程中具有實際意義的值的時間範圍。更通俗地說,變量的作用域是變量名字的性質,而變量的生存周期是變量本身的性質。

變量名字的作用域會影響它的生存周期。

作用域是變量語法方面的性質。多數語言對每一個變量(和其他名目實體)定義明確的作用域,這些作用域在同一個程序中可能不同。變量的作用域是指程序中的特定區域,在這些區域中,該變量的名字是有意義的並且變量是「可見的」。在進入作用域時,變量通常開始它的生命周期;而在離開作用域時,變量往往結束了它的生命周期。例如,某個變量的語法作用域僅在特定的語句塊或者子程序中。只有在某個函數中能訪問的變量則被稱為局部變量,在程序的任何一個地方都能引用的變量被稱為全局變量

生存周期,則是變量在運行時的性質。在運行時,每次變量與值的綁定都具有自己的生存周期。綁定的生存周期是程序執行過程中的一段時間,在這段時間內,變量始終被關聯到相同的值或者內存位置。在閉包的情況中,運行中的程序可能進入和離開某個生存周期很多次。

在一些代碼段中,在一個變量的作用域中可能未被賦值,或者它的值已經被銷毀掉了。這類變量常被稱為「生存周期外」或者「未綁定」。在很多語言中,試圖使用未綁定的變量是一個錯誤。在其他語言中,這種行為會產生不可預期的結果,這樣的變量可能被分配一個新的值。與之對照的是,一個變量綁定到一個超過他作用域的生存周期是被允許的,如Lisp的閉包和C語言的靜態局部變量。當程序再次執行到變量的作用域時,變量能再次被使用,但還保持上一次的值。

為了提高空間效率,變量需要的存儲空間可能要等到變量第一次使用時才申請,不再使用後就刪除。為了避免浪費空間,如果變量聲明了但不實際使用,編譯器通常會向程序員發出警告。

使變量的作用域儘可能的小,被認為是一個好的編程方式,這樣程序的不同部分就不會因為意外的改變對方的變量而互相影響了。實現上述目標的通常技術是讓程序的不同部分使用不同名字空間,或者通過動態變量作用使用各自的私有變量

很多程序設計語言使用保留的值(如NULL)表示沒有初始化的變量。

類型

靜態類型語言中,如JavaML,每個都變量有一個類型,也就是說只有給定種類的值能存儲到該變量中。一個基本類型的變量只能保存基本類型的值。一個類類型的變量能保存空值NULL,或者保存該類型或其子類型的對象。一個接口類型的變量能保存空值NULL,或者該接口的任何一個實現。一個數組類型能保存空值NULL或者一個數組。

動態類型語言中,如Python,是值,而不是變量來攜帶類型信息。在Common Lisp中,這兩種情況同時存在:變量在編譯時具有一個類型(如果沒有聲明,就假設這個類型為超類型T);值也有具有一個類型,該類型可以在運行時進行檢查和識別。

變量的類型也允許在編譯時多態決定。但是,這和面向對象的函數調用(在C++中稱為虛函數)的多態不同。

變量常常保存簡單的數據,如整數字符串。但有些程序設計語言允許變量同時表示多種數據類型。這些語言一般也允許函數參數多態,其函數對變量的操作可同時適用於多種數據類型。例如,函數length可以求一個列表的長度,如果length類型簽名中包含一個類型變量,就可以實現參數多態。這樣,求列表中的元素個數就與列表元素的類型無關了。

參數

函數的形式參數也被稱為變量。例如如下的C++代碼段:

int AddTwo(int x)
{
    return x + 2;
}

AddTwo(5);  // 结果为7

變量x是「形參」,因為當函數被調用時會被給定一個值。整數5是「實參」,它給x一個值。在多數語言中,函數參數具有局部的作用域。這裡的變量x只能在AddTwo函數中有效(儘管如此,其他函數也可以使用自己的變量x)。

內存分配

變量的內存空間分配和它們值的表示方法是多種多樣的,這種區別體現在語言之間,也體現在給定語言的內部使用上。很多語言都實現了局部變量的空間分配方式。局部變量保存在調用堆棧上,其生存周期維持在單個函數中,函數返回時這些內存會自動被回收。(更一般的講,變量的名字是和一些特定的連續內存塊的地址綁定,對變量的操作其實是對相應的內存塊進行操作。)對於巨大或者編譯時不知道大小的數據,更常用的方法是使用「引用」。 這時記錄是值的地址而不是值本身,它們是從一種被稱為「」的內存池中分配的。

綁定的變量具有值,一個抽象的值。在程序執行時,變量的值用計算機內存中存儲的一些數據對象來表示。程序,或者說運行時環境,必須為每個數據對象設置內存。由於內存是有限的,為了安置每一個數據對象,當數據對象不再表示某個變量的值時,相應的內存會被回收並重新使用。

在堆中分配的對象必須被釋放掉,特別是當對象不再被需要時。在具有垃圾回收機制的語言(如C#JavaLisp)中,當變量出了其作用域再也不能被引用時運行環境會自動地回收對象。在不具有垃圾回收機制的語言當中,如C語言,程序必須顯式地分配內存,而且使用結束後還要釋放內存,如果不這樣做則會造成內存泄漏。在這種情況下,程序運行過程中會逐漸消耗,最終因為內存耗盡而崩潰。

當一個變量指向動態創建的數據結構時,可能其中一些部分只能通過變量間接地訪問。在這種環境下,垃圾回收器(或者類似的語言特性)必須處理當變量回收時只有一部分內存能夠重新回收的情況。

名字替換