程式語言入門/型別定義
絕大多數程式語言都處理型別化的值,例如整數、布林值、實數、人員、車輛等。然而,也有一些程式語言根本沒有型別。這些程式語言往往非常簡單。這方面的典型例子是核心lambda演算和Brainfuck。還有一些程式語言擁有非常原始的型別系統。例如,x86彙編允許將浮點數、整數和地址儲存到同一個暫存器中。在這種情況下,用於處理暫存器的特定指令決定了要考慮的資料型別。例如,x86彙編有一個subl指令來執行整數減法,還有另一個指令fsubl,用來減去浮點值。再比如,BCPL只有一種資料型別,即一個字。不同的操作將每個字視為不同的型別。然而,大多數程式語言都有更復雜的型別,我們將在這章中討論這些型別系統。
我們現在應該回答的最重要的問題是“什麼是資料型別”。我們可以透過結合兩個概念來描述資料型別
- 值:本質上,型別是一組值。例如,許多程式語言中都有的布林資料型別就是一個包含兩個元素的集合:真和假。這些集合中有一些包含有限數量的元素,而另一些則是無限的。在Java中,整數資料型別是一個包含232個元素的集合;然而,字串資料型別是一個包含無限數量元素的集合。
- 操作:並非所有操作都可以在所有資料型別上應用。例如,我們可以對兩個數字型別求和;但是,在大多數程式語言中,對兩個布林值求和是沒有意義的。在x86彙編和BCPL中,操作區分記憶體位置的型別和其它位置的型別。
型別的存在是為了讓開發者能夠在程式中表示現實世界中的實體。但是,型別並不是它們所表示的實體。例如,Java中的整數型別代表從-231到231-1的數字。更大的數字無法表示。如果我們嘗試給Java中的整數賦值,比如231,那麼我們得到-231。之所以發生這種情況,是因為Java只允許我們表示任何二進位制整數的31個最低位。
型別在許多方面都是有用的。型別如此重要的事實證明了這一點,如今幾乎所有程式語言都使用型別,無論是靜態型別還是執行時型別。在使型別如此重要的眾多因素中,我們提到了
- 效率:由於不同的型別可以使用不同的方式表示,因此執行時環境可以為每種表示選擇最有效的替代方案。
- 正確性:型別可以防止程式進入未定義狀態。例如,如果將一個整數和一個浮點數相加的結果是未定義的,那麼執行時環境可以在此操作可能發生時觸發一個異常。
- 文件:型別是一種文件形式。例如,如果一個程式設計師知道一個給定變數是一個整數,那麼他或她就對該變量了解很多資訊。例如,程式設計師知道這個變數可以是算術運算的目標。程式設計師也知道分配該變數需要多少記憶體。此外,與對編譯器毫無意義的簡單註釋相反,型別是編譯器可以檢查的文件形式。
型別是一個引人入勝的主題,因為它們根據許多不同的維度對程式語言進行分類。三個最重要的維度是
- 靜態型別與動態型別。
- 強型別與弱型別。
- 結構型別與名義型別。
在任何程式語言中,都有兩種主要的型別類別:基本型別和構造型別。基本型別是原子的,也就是說,它們不是由其它型別的組合形成的。構造型別或複合型別,顧名思義,是由其它型別組成的,這些型別可以是基本型別,也可以是複合型別。在本章的剩餘部分,我們將展示每種型別家族的例子。