- 編程與類型系統
- (美)弗拉德·里斯庫迪亞
- 731字
- 2021-01-29 11:51:23
1.2.2 不可變性
我們可將運行中的系統視為正在通過狀態空間,而不可變性也與這種視角密切相關。當我們在一個好狀態中時,如果能夠保持該狀態下的一些部分不變,就減少了出錯的概率。
下面來看一個阻止除零運算的簡單例子。我們將檢查除數的值,如果除數為0,就拋出一個錯誤,如程序清單1.4所示。如果在檢查值之后,它還可以發生變化,那么檢查的價值就不大了。
程序清單1.4 不當修改

在真實的程序中,這種問題時常以不易察覺的方式出現:變量被另外一個并發執行的線程修改,或者被另外一個調用函數悄悄修改。與本例一樣,一旦值發生變化,執行檢查的保證就不再有效。如果像程序清單1.5中一樣,將x指定為常量,那么在試圖修改x時,將發生編譯錯誤。
程序清單1.5 不可變性

編譯器將拒絕編譯這個bug,并給出下面的錯誤消息:

從內存表示的角度來說,可變與不可變的x沒有區別。常量性只對編譯器有意義,它是類型系統啟用的一個屬性。
通過像這樣在類型前面加上const關鍵字,把狀態標記為不可改變,可以阻止修改變量,從而讓我們通過檢查得到的保證一直有效。當涉及并發時,不可變性特別有用,因為如果數據不可變,就不會發生數據競爭。
當處理不可變變量時,優化編譯器可以內聯這些變量的值,從而生成更加高效的代碼。一些函數編程語言使所有數據不可變:函數接受一些數據作為輸入,然后返回其他數據,在此過程中并不會修改輸入。在這種情況下,當我們驗證一個變量,確認它在好狀態下后,就保證了在該變量的整個生存期內,它都會在好狀態下。當然,這種處理方式意味著在本可以直接操作數據的地方并不直接操作數據,而是復制數據,這并非我們所期望的。
并不是在所有情況下都可以讓所有數據不可變。盡管如此,在合理的情況下讓盡可能多的數據不可變,能夠顯著減少不滿足先決條件或者數據競爭等問題。