fbpx
维基百科

型別系統

计算机科学中,类型系統(英語:type system)用于定義如何將程式語言中的數值和運算式归類为许多不同的型別,如何操作这些型別,这些型別如何互相作用。型別可以确认一个值或者一组值具有特定的意义和目的(雖然某些型別,如抽象型別和函式型別,在程式執行中,可能不表示為值)。型別系統在各種語言之間有非常大的不同,也許,最主要的差異存在於編譯時期的語法,以及執行時期的操作实现方式。

編譯器可能使用值的靜態型別以最佳化所需的儲存區,並選取對值運算時的較佳演算法。例如,在許多C編譯器中,「浮點數」資料型別是以32 位元表示,與IEEE 754規格一致的單精度浮點數。因此,在數值運算上,C應用了浮点数規範(浮點數加法、乘法等等)。

型別的約束程度以及評估方法,影響了語言的型別。更進一步,程式語言可能就型別多態性部分,對每一個型別都對應了一個極度個別的演算法的運算。型別理論研究型別系統,儘管實際的程式語言型別系統,起源於電腦架構的實際問題、編譯器實作,以及語言設計。

基礎

定型(typing,又稱型別指派)賦予一組位元某個意義。型別通常和記憶體中的數值或物件(如變數)相聯繫。因為在電腦中,任何數值都是以一組位元簡單組成的,硬體無法區分記憶體位址指令碼字元整數、以及浮點數。型別可以告知程式和程式設計者,應該怎麼對待那些位元。

型別系統提供的主要功能有:

  • 安全性
使用型別可允許編譯器偵測無意義的,或者是可能無效的代碼。例如,可以識出一個無效的運算式"Hello, World" + 3,因為不能對(在平常的直覺中)逐字字串加上一個整數。強型別提供更多的安全性,但它並不能保證絕對安全(詳情請見型別安全)。
  • 最佳化
靜態型別檢查可提供有用的資訊給編譯器。例如,如果一個型別指明某個值必須以4的倍數對齊,編譯器就有可以使用更有效率的機器指令。
  • 可讀性
在更具表現力的型別系統中,若其可以闡明程式設計者的意圖的話,型別就可以充當為一種文件形式。例如,時間戳記可以是整數的子型別;但如果程式設計者宣告一個函式為返回一個時間戳記,而不只是一個整數,這個函式就能表現出一部分文件的闡釋性。
  • 抽象化(或模組化
型別允許程式設計者對程式以較高層次的方式思考,而不是煩人的低層次實作。例如,程式設計者可以將字串想成一個值,以此取代僅僅是位元組的陣列。或者型別允許程式設計者表達兩個子系統之間的介面。將子系統間互動時的必要定義加以定位,防止子系統間的通訊發生衝突。

程式通常對每一個值關聯一個特定的型別(儘管一個型別可以有一個以上的子型別)。其它的實體,如物件模組、通訊頻道、依賴關係,或者純粹的型別自己,可以和一個型別關聯。例如:

一個數值的型別
一個物件的型別
  • 種類
一個型別的型別

在每一個程式語言中,都有一個特定的型別系統,保證程式的表現良好,並且排除違規的行為。作用系統對型別系統提供更多細微的控制。

类型

 :断言变量e的类型是int。

型別檢查

型別檢查所進行的檢驗處理以及實行型別的約束,可發生在編譯時期(靜態檢查)或執行時期(動態檢查)。靜態型別檢查是在編譯器所進行語義分析中進行的。如果一個語言強制實行型別規則(即通常只允許以不遺失資訊為前提的自動型別轉換)就稱此處理為強型別,反之稱為弱型別

靜態和動態檢查

如果一個程式語言的型別檢查,可在不測試執行時期運算式的等價性的情況下進行,該語言即為靜態型別的。一個靜態型別的程式語言,是在執行時期和編譯時期之間的處理階段下重視這些區別的。如果程式的獨立模組,可進行各自的型別檢查(獨立編譯),而無須所有會在執行時出現的模組的那些資訊,該語言即具有一個編譯時期階段。如果一個程式語言支援執行時期(動態)調度已標記的資料,該語言即為動態型別的。如果一個程式語言破壞了階段的區別,因而型別檢查需要測試執行時期的運算式的等價性,該語言即為依存型別的。[1]

在動態型別中,經常在執行時期進行型別標記的檢查,因為變數所約束的值,可經由執行路徑獲得不同的標記。在靜態型別程式語言中,型別標記使用辨識聯合型別表示。

動態型別經常出現於腳本語言RAD語言中。動態型別在解释型语言中極為普遍,編譯語言則偏好無須執行時期標記的靜態型別。對於型別和隱式型別語言較完整的列表參見型別和隱式型別語言。

術語推斷型別鸭子类型,duck typing)指的是動態型別在語言中的應用方式,它會「推斷」一個數值的型別。

看看型別標記檢查是如何運作的,考慮下列假碼範例:

var x; //(1) x := 5; //(2) x := "hi"; //(3) 

在這個範例中,(1)宣告x;(2)將整數值5代給x;(3)將字串值"hi"代給x。在主要的靜態系統中,這個代碼片斷將會違反規則,因為(2)和(3)對 x所約束的型別相矛盾。

相較之下,一個純粹的動態型別系統允許上述程式的執行,因為型別標記附到數值上(不是變數)。在處理錯誤語句或運算式的時候,以動態型別實作的語言會捕捉程式的錯誤,而不是誤用錯誤型別的數值。換句話說,動態型別捕捉在程式執行時的錯誤。

典型的動態型別實作,會以型別標記維持程式所有數值的「標記」,並在運算任何數值之前檢查標記。例如:

var x := 5; //(1) var y := "hi"; //(2) var z := x + y; //(3) 

在這個程式片斷中,(1)將數值5約束給x;(2)將數值"hi"約束給y;以及(3)嘗試將x加到y。在動態型別語言中,約束給x的值會是一對整數, 5),且約束給y的值會是一對字串, "hi")。當這個程式嘗試執行第3行時,語言對型別標記整數字串進行檢查,如果這兩個型別的+(加法)運算尚未定義,就會發出一個錯誤。

某些靜態語言有一個「後門」,在這些程式語言中,能夠編寫一些不被靜態型別所檢查的代碼。例如,Java和C-風格的語言有「轉型」可用。在靜態型別的程式語言中,不必然意味著缺乏動態型別機制。例如Java使用靜態型別,但某些運算需要支援執行時期的型別測試,這就是動態型別的一種形式。更多靜態和動態型別的討論,請參閱程式語言

實踐中的靜態和動態型別檢查

對靜態型別和動態型別兩者之間的權衡也是必要的。

靜態型別在編譯時期時,就能可靠地發現型別錯誤。因此通常能增進最終程式的可靠性。然而,有多少的型別錯誤發生,以及有多少比例的錯誤能被靜態型別所捕捉,目前對此仍有爭論。靜態型別的擁護者認為,當程式通過型別檢查時,它才有更高的可靠性。雖然動態型別的擁護者指出,實際流通的軟體證明,兩者在可靠性上並沒有多大差別。可以認為靜態型別的價值,在於增進型別系統的強化。強型別語言(如MLHaskell)的擁護者提出,幾乎所有的bug都可以看作是型別錯誤,如果編寫者以足夠恰當的方式,或者由編譯器推斷來宣告一個型別。[2]

靜態型別通常可以編譯出速度較快的代碼。當編譯器清楚知道所要使用的資料型別,就可以產生最佳化過後的機器碼。更進一步,靜態型別語言中的編譯器,可以更輕易地發現較佳捷徑。某些動態語言(如Common Lisp)允許任意型別的宣告,以便於最佳化。以上理由使靜態型別更為普及。參閱最佳化

相較之下,動態型別允許編譯器和解譯器更快速的運作。因為原始碼在動態型別語言中,變更為減少進行檢查,並減少解析代碼。這也可減少編輯-編譯-測試-除錯的週期。

靜態型別語言缺少型別推斷(如Java),而需要編寫者宣告所要使用的方法或函式的型別。編譯器將不允許編寫者忽略,這可為程式起附加性說明文件的作用。但靜態型別語言也可以無須型別宣告,所以與其說是靜態型別的代價,倒不如說是型別宣告的報酬。

靜態型別允許建構函式庫,它們的使用者不太可能意外的誤用。這可作為傳達函式庫開發者意圖的額外機制。

動態型別允許建構一些靜態型別系統所做不出來的東西。例如,eval函式,它使得執行任意資料作為代碼成為可能(不過其代碼的型別仍是靜態的)。此外,動態型別容納過渡代碼和原型設計,如允許使用字串代替資料結構。靜態型別語言最近的增強(如Haskell 一般化代數資料型別)允許eval函式以型別安全的方式撰寫。

動態型別使元程式設計更為強大,且更易於使用。例如C++模板的寫法,比起等價的RubyPython寫法要來的麻煩。更高度的執行時期構成物,如元類別(metaclass)和內觀(Introspection),對靜態型別語言而言通常更為困難。

強型別和弱型別

強型別的基本定義即為,禁止錯誤型別的參數繼續運算。C語言的型別轉換即為缺乏強型別的證例;如果編寫者用C語言對一個值轉換型別,不僅令編譯器允許這個代碼,而且在執行時期中也同樣允許。這使得C代碼可更為緊密和快速,不過也使除錯變的更為困難。

部分學者使用術語記憶體安全語言(或簡稱為安全語言)形容禁止未定義運算發生的語言。例如,某個記憶體安全語言將會檢查陣列邊界

弱型別意指一個語言可以隱式的轉換型別(或直接轉型)。看看先前的例子:

var x := 5; var y := "37"; x + y; 

在弱型別語言中編寫上述代碼,並不清楚將會得到哪一種結果。某些語言如Visual Basic,將會產生可以運作的代碼,它將會給出的結果是42:系統將字串"37"轉換成數字37,以符合運算上的直覺;其它的語言,像JavaScript將會產生的結果是"537":系統將數字5轉換成字串"5"並把兩者串接起來。在Visual Basic和JavaScript中,最終的型別是以那兩個運算元為考量的規則所決定。在部分語言中,如AppleScript,某個值最終的型別,只以最左邊的運算元的型別所決定。

設計精巧的語言也允許語言顯現出弱型別(藉由类型推断之類的技術)的特性以方便使用,並且保留了強型別語言所提供的型別檢查和保護。例子包括VB.NetC#以及Java

運算子多載所帶來的簡化,像是不以算術運算中的加法來使用「+」,可以減少一些由動態型別所造成的混亂。例如,部分語言使用「.」或「&」來串連字串。

型別系統的安全性

程式語言的型別系統的第三種分類方法,就是型別運算和轉換的安全性。如果它不允許導致不正確的情況的運算或轉換,電腦科學就認為該語言是「型別安全」的。

再次看看這個假碼例子:

var x := 5; var y := "37"; var z := x + y; 

在一個如Visual Basic的語言中,例子中的變數z得到的值為42。不管編寫者有沒有這個意圖,該語言定義了明確的結果,且程式不會就此崩潰,或將不明定義的值賦給z。就這方面而言,這樣的語言就是型別安全的。

現在來看C的相同例子:

int x = 5; char y[] = "37"; char* z = x + y; 

在這個例子中,z將會指向一個超過y位址5個位元組的記憶體位址,相當於指向y字串的指標之後的兩個空字元之處。這個位址的內容尚未定義,且有可能超出記憶體的定址界線,而且就這麼引用參考z會引起程式的終止。雖是一個良好型別,但卻不是記憶體安全的程式——如果以對型別安全語言而言不該發生為先決條件的話。

多態性和型別

術語「多態性」指的是:代碼(尤其是函式和類別)對各種型別的值能夠動作,或是相同資料結構的不同實體能夠控制不同型別的元素。為了提升複用代碼的潛在價值,型別系統逐漸允許多態性:在具有多態性的語言中,程式設計者只需要實作如列表或詞典的資料結構一次,而不是對使用到它的元素的每一個型別都規劃一次。基於這個原因,電腦學家也稱使用了一定的多態性的方法為泛型程式設計。型別理論的多態性基礎與抽象化模組化和(偶爾)子型別有相當密切的聯繫關係。

推斷型別

推斷型別(鸭子类型,Duck typing)最初是由Dave Thomas在Ruby社群中提出的,推斷型別用了這個論證法「如果它像什麼,而且其它地方也像什麼,那麼它就是什麼。」

在某些程式設計環境中,兩個物件可以有相同的型別,即使它們沒有什麼交集。一個例子是C++迭代器和指针所拥有的的雙重性,兩者皆以不甚相同的機制實作並提供一個* 運算。

這個技術之所以常被稱作「鴨子型別」,是基於這句格言:「如果它搖搖擺擺的走法很像鴨子,而且它的嘎嘎叫聲也像鴨子,那它就是一隻鴨子!」

"If it waddles like a duck, and quacks like a duck, it's a duck!"

顯示宣告和隱式暗示

許多靜態型別系統,如C和Java,要求要宣告型別:編寫者必須以指定型別明確地關聯到每一個變數上。其它的,如Haskell,則進行型別推斷:編譯器根據編寫者如何運用這些變數,以草擬出關於這個變數的型別的結論。例如,給定一個函式f(x,y),它將xy加起來,編譯器可以推斷出xy必須是數字——因為加法僅定義給數字。因此,任何在其它地方以非數值型別(如字串或鏈表)作為參數來呼叫f的話,將會發出一個錯誤。

在代碼中數值、字串常數以及運算式,經常可以在詳細的前後文中暗示型別。例如,一個運算式3.14可暗示浮點數型別;而[1, 2, 3]則可暗示一個整數的鏈表;通常是一個陣列

型別的型別

型別的型別是一種種類。在型別程式設計中有明確的種類,如Haskell程式語言型別建構子,在申請比較簡單的型別之後,其返回一個簡單的型別。例如,型別建構子二選一有這些種類* -> * -> **代表種類),而且它的申請二選一字串整數是一個簡單的型別。然而,大多數程式語言的型別,是由編寫者來暗示或寫死,這就並未將種類的概念用作為首選層。

型別可分為幾個大類:

這是最簡單的型別種類,例如:整數浮點數
全部是數字的型別,例如:整數和自然數
以浮點數表示數字的型別
由基本型別組合成的型別,例如:陣列記錄單元抽象資料型別具有複合型別和界面兩種屬性,這取決於你提及哪一個。
例如:變數型別
例如:二元函數
如參數化型別、型別變數
模組
  • 精煉型別
識別其它型別的子集的型別
取決於執行時期的數值的型別
  • 所有權型別
描述或約束物件導向系統結構的型別

相容性:等價性和子型別

對於靜態型別語言的型別檢查器,必須檢驗所有運算式的型別,是否與前後文所期望的型別一致。例如指派語句x := e,推斷運算式e的型別,必定與宣告或推斷的變數型別x一致。這個一致性的概念,就稱為相容性,是每一個程式語言所特有的。

很明顯,如果ex的型別相同,就允許指派,然後這是一個有效的運算式。因此在最簡單的型別系統中,問題從兩個型別是否相容,簡化為兩個型別是否相等(或等價)。然而不同的語言對於兩個型別運算式是否理解為表示了相同型別,有著不同的標準。型別的相等理論的差異相當巨大,兩個極端的例子是結構型別系統(Structural type system),任兩個以相同結構所描述的值的型別都是等價的,且在標明型別系統(Nominative type system)上,沒有兩個獨特的語法構成的型別運算式表示同一型別,(型別若要相等,就必須具有相同的「名字」)。

子型別的語言中,相容關係更加複雜。特別是如果AB的子型別,那麼型別A的值可用於型別B也屬意料之中,但反過來就不是這樣。如同等價性,對每一個程式語言而言,子型別的關係的定義是不同的,可能存在各種變化。在語言中出現的參數或者特定的多態性,也可能意味著具有對型別的相容性。

爭議

在強型別、靜態型別語言的支持者,和動態型別、自由形式的支持者之間,經常發生爭執。前者主張,在編譯的時候就可以較早發現錯誤,而且還可增進執行時期的效能。後者主張,使用更加動態的型別系統,分析程式碼更為簡單,減少出錯機會,才能更加輕鬆快速的編寫程式。[3]與此相關的是,考慮到在型別推斷的程式語言中,通常不需要手動宣告型別,這部分的額外開銷也就自動降低了。

参考文献

  1. ^ Harper, Robert & Benjamin C. Pierce (2005), "Design Considerations for ML-Style Module Systems", in Pierce, Benjamin C., Advanced Topics in Types and Programming Languages, Cambridge, MA: MIT Press, ISBN 0262162288 (页面存档备份,存于互联网档案馆
  2. ^ 存档副本. [2007-03-24]. (原始内容于2008-05-12). 
  3. ^ Meijer, Erik and Peter Drayton. (PDF). Microsoft Corporation. (原始内容 (PDF)存档于2007-02-16). 

參閱

型別系統, 在计算机科学中, 类型系統, 英語, type, system, 用于定義如何將程式語言中的數值和運算式归類为许多不同的型別, 如何操作这些型別, 这些型別如何互相作用, 型別可以确认一个值或者一组值具有特定的意义和目的, 雖然某些型別, 如抽象型別和函式型別, 在程式執行中, 可能不表示為值, 在各種語言之間有非常大的不同, 也許, 最主要的差異存在於編譯時期的語法, 以及執行時期的操作实现方式, 編譯器可能使用值的靜態型別以最佳化所需的儲存區, 並選取對值運算時的較佳演算法, 例如, 在許多c編譯器. 在计算机科学中 类型系統 英語 type system 用于定義如何將程式語言中的數值和運算式归類为许多不同的型別 如何操作这些型別 这些型別如何互相作用 型別可以确认一个值或者一组值具有特定的意义和目的 雖然某些型別 如抽象型別和函式型別 在程式執行中 可能不表示為值 型別系統在各種語言之間有非常大的不同 也許 最主要的差異存在於編譯時期的語法 以及執行時期的操作实现方式 編譯器可能使用值的靜態型別以最佳化所需的儲存區 並選取對值運算時的較佳演算法 例如 在許多C編譯器中 浮點數 資料型別是以32 位元表示 與IEEE 754規格一致的單精度浮點數 因此 在數值運算上 C應用了浮点数規範 浮點數加法 乘法等等 型別的約束程度以及評估方法 影響了語言的型別 更進一步 程式語言可能就型別多態性部分 對每一個型別都對應了一個極度個別的演算法的運算 型別理論研究型別系統 儘管實際的程式語言型別系統 起源於電腦架構的實際問題 編譯器實作 以及語言設計 目录 1 基礎 2 类型 3 型別檢查 3 1 靜態和動態檢查 3 2 實踐中的靜態和動態型別檢查 3 3 強型別和弱型別 3 4 型別系統的安全性 4 多態性和型別 4 1 推斷型別 5 顯示宣告和隱式暗示 6 型別的型別 7 相容性 等價性和子型別 8 爭議 9 参考文献 10 參閱基礎 编辑定型 typing 又稱型別指派 賦予一組位元某個意義 型別通常和記憶體中的數值或物件 如變數 相聯繫 因為在電腦中 任何數值都是以一組位元簡單組成的 硬體無法區分記憶體位址 指令碼 字元 整數 以及浮點數 型別可以告知程式和程式設計者 應該怎麼對待那些位元 型別系統提供的主要功能有 安全性使用型別可允許編譯器偵測無意義的 或者是可能無效的代碼 例如 可以識出一個無效的運算式 Hello World 3 因為不能對 在平常的直覺中 逐字字串加上一個整數 強型別提供更多的安全性 但它並不能保證絕對安全 詳情請見型別安全 最佳化靜態型別檢查可提供有用的資訊給編譯器 例如 如果一個型別指明某個值必須以4的倍數對齊 編譯器就有可以使用更有效率的機器指令 可讀性在更具表現力的型別系統中 若其可以闡明程式設計者的意圖的話 型別就可以充當為一種文件形式 例如 時間戳記可以是整數的子型別 但如果程式設計者宣告一個函式為返回一個時間戳記 而不只是一個整數 這個函式就能表現出一部分文件的闡釋性 抽象化 或模組化 型別允許程式設計者對程式以較高層次的方式思考 而不是煩人的低層次實作 例如 程式設計者可以將字串想成一個值 以此取代僅僅是位元組的陣列 或者型別允許程式設計者表達兩個子系統之間的介面 將子系統間互動時的必要定義加以定位 防止子系統間的通訊發生衝突 程式通常對每一個值關聯一個特定的型別 儘管一個型別可以有一個以上的子型別 其它的實體 如物件 模組 通訊頻道 依賴關係 或者純粹的型別自己 可以和一個型別關聯 例如 資料型別一個數值的型別類別一個物件的型別種類一個型別的型別在每一個程式語言中 都有一個特定的型別系統 保證程式的表現良好 並且排除違規的行為 作用系統對型別系統提供更多細微的控制 类型 编辑e i n t displaystyle e int 断言变量e的类型是int 型別檢查 编辑型別檢查所進行的檢驗處理以及實行型別的約束 可發生在編譯時期 靜態檢查 或執行時期 動態檢查 靜態型別檢查是在編譯器所進行語義分析中進行的 如果一個語言強制實行型別規則 即通常只允許以不遺失資訊為前提的自動型別轉換 就稱此處理為強型別 反之稱為弱型別 靜態和動態檢查 编辑 如果一個程式語言的型別檢查 可在不測試執行時期運算式的等價性的情況下進行 該語言即為靜態型別的 一個靜態型別的程式語言 是在執行時期和編譯時期之間的處理階段下重視這些區別的 如果程式的獨立模組 可進行各自的型別檢查 獨立編譯 而無須所有會在執行時出現的模組的那些資訊 該語言即具有一個編譯時期階段 如果一個程式語言支援執行時期 動態 調度已標記的資料 該語言即為動態型別的 如果一個程式語言破壞了階段的區別 因而型別檢查需要測試執行時期的運算式的等價性 該語言即為依存型別的 1 在動態型別中 經常在執行時期進行型別標記的檢查 因為變數所約束的值 可經由執行路徑獲得不同的標記 在靜態型別程式語言中 型別標記使用辨識聯合型別表示 動態型別經常出現於腳本語言和RAD語言中 動態型別在解释型语言中極為普遍 編譯語言則偏好無須執行時期標記的靜態型別 對於型別和隱式型別語言較完整的列表參見型別和隱式型別語言 術語推斷型別 鸭子类型 duck typing 指的是動態型別在語言中的應用方式 它會 推斷 一個數值的型別 看看型別標記檢查是如何運作的 考慮下列假碼範例 var x 1 x 5 2 x hi 3 在這個範例中 1 宣告x 2 將整數值5代給x 3 將字串值 hi 代給x 在主要的靜態系統中 這個代碼片斷將會違反規則 因為 2 和 3 對 x所約束的型別相矛盾 相較之下 一個純粹的動態型別系統允許上述程式的執行 因為型別標記附到數值上 不是變數 在處理錯誤語句或運算式的時候 以動態型別實作的語言會捕捉程式的錯誤 而不是誤用錯誤型別的數值 換句話說 動態型別捕捉在程式執行時的錯誤 典型的動態型別實作 會以型別標記維持程式所有數值的 標記 並在運算任何數值之前檢查標記 例如 var x 5 1 var y hi 2 var z x y 3 在這個程式片斷中 1 將數值5約束給x 2 將數值 hi 約束給y 以及 3 嘗試將x加到y 在動態型別語言中 約束給x的值會是一對 整數 5 且約束給y的值會是一對 字串 hi 當這個程式嘗試執行第3行時 語言對型別標記整數和字串進行檢查 如果這兩個型別的 加法 運算尚未定義 就會發出一個錯誤 某些靜態語言有一個 後門 在這些程式語言中 能夠編寫一些不被靜態型別所檢查的代碼 例如 Java和C 風格的語言有 轉型 可用 在靜態型別的程式語言中 不必然意味著缺乏動態型別機制 例如Java使用靜態型別 但某些運算需要支援執行時期的型別測試 這就是動態型別的一種形式 更多靜態和動態型別的討論 請參閱程式語言 實踐中的靜態和動態型別檢查 编辑 對靜態型別和動態型別兩者之間的權衡也是必要的 靜態型別在編譯時期時 就能可靠地發現型別錯誤 因此通常能增進最終程式的可靠性 然而 有多少的型別錯誤發生 以及有多少比例的錯誤能被靜態型別所捕捉 目前對此仍有爭論 靜態型別的擁護者認為 當程式通過型別檢查時 它才有更高的可靠性 雖然動態型別的擁護者指出 實際流通的軟體證明 兩者在可靠性上並沒有多大差別 可以認為靜態型別的價值 在於增進型別系統的強化 強型別語言 如ML和Haskell 的擁護者提出 幾乎所有的bug都可以看作是型別錯誤 如果編寫者以足夠恰當的方式 或者由編譯器推斷來宣告一個型別 2 靜態型別通常可以編譯出速度較快的代碼 當編譯器清楚知道所要使用的資料型別 就可以產生最佳化過後的機器碼 更進一步 靜態型別語言中的編譯器 可以更輕易地發現較佳捷徑 某些動態語言 如Common Lisp 允許任意型別的宣告 以便於最佳化 以上理由使靜態型別更為普及 參閱最佳化 相較之下 動態型別允許編譯器和解譯器更快速的運作 因為原始碼在動態型別語言中 變更為減少進行檢查 並減少解析代碼 這也可減少編輯 編譯 測試 除錯的週期 靜態型別語言缺少型別推斷 如Java 而需要編寫者宣告所要使用的方法或函式的型別 編譯器將不允許編寫者忽略 這可為程式起附加性說明文件的作用 但靜態型別語言也可以無須型別宣告 所以與其說是靜態型別的代價 倒不如說是型別宣告的報酬 靜態型別允許建構函式庫 它們的使用者不太可能意外的誤用 這可作為傳達函式庫開發者意圖的額外機制 動態型別允許建構一些靜態型別系統所做不出來的東西 例如 eval函式 它使得執行任意資料作為代碼成為可能 不過其代碼的型別仍是靜態的 此外 動態型別容納過渡代碼和原型設計 如允許使用字串代替資料結構 靜態型別語言最近的增強 如Haskell 一般化代數資料型別 允許eval函式以型別安全的方式撰寫 動態型別使元程式設計更為強大 且更易於使用 例如C 模板的寫法 比起等價的Ruby或Python寫法要來的麻煩 更高度的執行時期構成物 如元類別 metaclass 和內觀 Introspection 對靜態型別語言而言通常更為困難 強型別和弱型別 编辑 主条目 強型別 強型別的基本定義即為 禁止錯誤型別的參數繼續運算 C語言的型別轉換即為缺乏強型別的證例 如果編寫者用C語言對一個值轉換型別 不僅令編譯器允許這個代碼 而且在執行時期中也同樣允許 這使得C代碼可更為緊密和快速 不過也使除錯變的更為困難 部分學者使用術語記憶體安全語言 或簡稱為安全語言 形容禁止未定義運算發生的語言 例如 某個記憶體安全語言將會檢查陣列邊界 弱型別意指一個語言可以隱式的轉換型別 或直接轉型 看看先前的例子 var x 5 var y 37 x y 在弱型別語言中編寫上述代碼 並不清楚將會得到哪一種結果 某些語言如Visual Basic 將會產生可以運作的代碼 它將會給出的結果是42 系統將字串 37 轉換成數字37 以符合運算上的直覺 其它的語言 像JavaScript將會產生的結果是 537 系統將數字5轉換成字串 5 並把兩者串接起來 在Visual Basic和JavaScript中 最終的型別是以那兩個運算元為考量的規則所決定 在部分語言中 如AppleScript 某個值最終的型別 只以最左邊的運算元的型別所決定 設計精巧的語言也允許語言顯現出弱型別 藉由类型推断之類的技術 的特性以方便使用 並且保留了強型別語言所提供的型別檢查和保護 例子包括VB Net C 以及Java 運算子多載所帶來的簡化 像是不以算術運算中的加法來使用 可以減少一些由動態型別所造成的混亂 例如 部分語言使用 或 amp 來串連字串 型別系統的安全性 编辑 主条目 型別安全 程式語言的型別系統的第三種分類方法 就是型別運算和轉換的安全性 如果它不允許導致不正確的情況的運算或轉換 電腦科學就認為該語言是 型別安全 的 再次看看這個假碼例子 var x 5 var y 37 var z x y 在一個如Visual Basic的語言中 例子中的變數z得到的值為42 不管編寫者有沒有這個意圖 該語言定義了明確的結果 且程式不會就此崩潰 或將不明定義的值賦給z 就這方面而言 這樣的語言就是型別安全的 現在來看C的相同例子 int x 5 char y 37 char z x y 在這個例子中 z將會指向一個超過y位址5個位元組的記憶體位址 相當於指向y字串的指標之後的兩個空字元之處 這個位址的內容尚未定義 且有可能超出記憶體的定址界線 而且就這麼引用參考z會引起程式的終止 雖是一個良好型別 但卻不是記憶體安全的程式 如果以對型別安全語言而言不該發生為先決條件的話 多態性和型別 编辑主条目 多型 術語 多態性 指的是 代碼 尤其是函式和類別 對各種型別的值能夠動作 或是相同資料結構的不同實體能夠控制不同型別的元素 為了提升複用代碼的潛在價值 型別系統逐漸允許多態性 在具有多態性的語言中 程式設計者只需要實作如列表或詞典的資料結構一次 而不是對使用到它的元素的每一個型別都規劃一次 基於這個原因 電腦學家也稱使用了一定的多態性的方法為泛型程式設計 型別理論的多態性基礎與抽象化 模組化和 偶爾 子型別有相當密切的聯繫關係 推斷型別 编辑 主条目 鸭子类型 推斷型別 鸭子类型 Duck typing 最初是由Dave Thomas在Ruby社群中提出的 推斷型別用了這個論證法 如果它像什麼 而且其它地方也像什麼 那麼它就是什麼 在某些程式設計環境中 兩個物件可以有相同的型別 即使它們沒有什麼交集 一個例子是C 中迭代器和指针所拥有的的雙重性 兩者皆以不甚相同的機制實作並提供一個 運算 這個技術之所以常被稱作 鴨子型別 是基於這句格言 如果它搖搖擺擺的走法很像鴨子 而且它的嘎嘎叫聲也像鴨子 那它就是一隻鴨子 If it waddles like a duck and quacks like a duck it s a duck 顯示宣告和隱式暗示 编辑許多靜態型別系統 如C和Java 要求要宣告型別 編寫者必須以指定型別明確地關聯到每一個變數上 其它的 如Haskell 則進行型別推斷 編譯器根據編寫者如何運用這些變數 以草擬出關於這個變數的型別的結論 例如 給定一個函式f x y 它將x和y加起來 編譯器可以推斷出x和y必須是數字 因為加法僅定義給數字 因此 任何在其它地方以非數值型別 如字串或鏈表 作為參數來呼叫f的話 將會發出一個錯誤 在代碼中數值 字串常數以及運算式 經常可以在詳細的前後文中暗示型別 例如 一個運算式3 14可暗示浮點數型別 而 1 2 3 則可暗示一個整數的鏈表 通常是一個陣列 型別的型別 编辑型別的型別是一種種類 在型別程式設計中有明確的種類 如Haskell程式語言的型別建構子 在申請比較簡單的型別之後 其返回一個簡單的型別 例如 型別建構子二選一有這些種類 gt gt 代表種類 而且它的申請二選一字串整數是一個簡單的型別 然而 大多數程式語言的型別 是由編寫者來暗示或寫死 這就並未將種類的概念用作為首選層 型別可分為幾個大類 原始型別這是最簡單的型別種類 例如 整數和浮點數整數型別全部是數字的型別 例如 整數和自然數浮點數型別以浮點數表示數字的型別複合型別由基本型別組合成的型別 例如 陣列或記錄單元 抽象資料型別具有複合型別和界面兩種屬性 這取決於你提及哪一個 子型別 衍生型別 物件型別例如 變數型別不完全型別 遞迴型別 函式型別例如 二元函數全稱量化型別如參數化型別 型別變數存在量化型別如模組精煉型別識別其它型別的子集的型別依存型別取決於執行時期的數值的型別所有權型別描述或約束物件導向系統結構的型別相容性 等價性和子型別 编辑對於靜態型別語言的型別檢查器 必須檢驗所有運算式的型別 是否與前後文所期望的型別一致 例如指派語句x i e i 推斷運算式e的型別 必定與宣告或推斷的變數型別x一致 這個一致性的概念 就稱為相容性 是每一個程式語言所特有的 很明顯 如果e和x的型別相同 就允許指派 然後這是一個有效的運算式 因此在最簡單的型別系統中 問題從兩個型別是否相容 簡化為兩個型別是否相等 或等價 然而不同的語言對於兩個型別運算式是否理解為表示了相同型別 有著不同的標準 型別的相等理論的差異相當巨大 兩個極端的例子是結構型別系統 Structural type system 任兩個以相同結構所描述的值的型別都是等價的 且在標明型別系統 Nominative type system 上 沒有兩個獨特的語法構成的型別運算式表示同一型別 即型別若要相等 就必須具有相同的 名字 在子型別的語言中 相容關係更加複雜 特別是如果A是B的子型別 那麼型別A的值可用於型別B也屬意料之中 但反過來就不是這樣 如同等價性 對每一個程式語言而言 子型別的關係的定義是不同的 可能存在各種變化 在語言中出現的參數或者特定的多態性 也可能意味著具有對型別的相容性 爭議 编辑在強型別 靜態型別語言的支持者 和動態型別 自由形式的支持者之間 經常發生爭執 前者主張 在編譯的時候就可以較早發現錯誤 而且還可增進執行時期的效能 後者主張 使用更加動態的型別系統 分析程式碼更為簡單 減少出錯機會 才能更加輕鬆快速的編寫程式 3 與此相關的是 考慮到在型別推斷的程式語言中 通常不需要手動宣告型別 這部分的額外開銷也就自動降低了 参考文献 编辑 Harper Robert amp Benjamin C Pierce 2005 Design Considerations for ML Style Module Systems in Pierce Benjamin C Advanced Topics in Types and Programming Languages Cambridge MA MIT Press ISBN 0262162288 页面存档备份 存于互联网档案馆 存档副本 2007 03 24 原始内容存档于2008 05 12 Meijer Erik and Peter Drayton Static Typing Where Possible Dynamic Typing When Needed The End of the Cold War Between Programming Languages PDF Microsoft Corporation 原始内容 PDF 存档于2007 02 16 參閱 编辑維基教科書中的相關電子教程 Types維基教科書中的相關電子教程 Class Declarations運算子多載 多型 電腦科學 程式語言 Type signature Signedness 型別系統參考表 取自 https zh wikipedia org w index php title 類型系統 amp oldid 75304325, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。