[英]Why shouldn't I store into literal arrays in Smalltalk?
一些樣式指南和習語表明你不應該改變文字數組,就像在這種情況下:
MyClass>>incrementedNumbers
| numbers |
numbers := #( 1 2 3 4 5 6 7 8 ).
1 to: numbers size: do: [:index |
numbers at: index put: (numbers at: index) + 1].
^ numbers
我為什么不這樣做?
注意:以下是依賴於實現的。 ANSI Smalltalk標准定義:
未指定相同文字的值是相同還是不同的對象。 還未指定特定文字的單獨評估的值是相同還是不同的對象。
也就是說,你不能依賴兩個(相等的)文字是相同的或不同的。 但是,以下是一種常見的實現方式
至少在Squeak和Pharo中,在保存(=編譯)方法時構造文字數組,並將其存儲在方法對象( CompiledMethod
)中。 這意味着更改文字數組會更改存儲在方法對象中的值。 例如:
MyClass>>example1
| literalArray |
literalArray := #( true ).
literalArray first ifTrue: [
literalArray at: 1 put: false.
^ 1].
^ 2
此方法僅在第一次調用時返回1
:
| o p |
o := MyClass new.
o example1. "==> 1"
o example1. "==> 2"
o example1. "==> 2"
p := MyClass new.
p example1. "==> 2"
這甚至獨立於接收器。
但同樣, 你不能依賴它 ,它可能與其他Smalltalks不同。
復制(始終安全)
為了克服這個問題,您可以在使用前簡單地復制文字數組。 你的例子:
MyClass>>incrementedNumbers | numbers | numbers := #( 1 2 3 4 5 6 7 8 ) copy. "<====== " 1 to: numbers size: do: [:index | numbers at: index put: (numbers at: index) + 1]. ^ numbers
這總是安全的,不會改變方法對象中的數組。
支撐陣列(主要是便攜式)
雖然未在標准中定義,但大多數實現都支持這樣的支撐數組表達式:
{ 1 . 'foo' . 2 + 3 }.
這相當於:
Array with: 1 with: 'foo' with: 2 + 3.
這些數組是在執行時構造的(與文字數組相反),因此可以安全使用。 再次舉例:
MyClass>>incrementedNumbers | numbers | numbers := { 1 . 2 . 3 . 4 . 5 . 6 . 7 . 8 }. "<====== " 1 to: numbers size: do: [:index | numbers at: index put: (numbers at: index) + 1]. ^ numbers
實際上有時會有理由改變文字數組(或者更常見的是任何方法文字,坦率地說)。 例如,如果您有靜態信息,如圖像或二進制數據,它們根本不會更改但不會一直使用,但您不能(無論出於何種原因)使用實例或類變量,您可以將對象存儲在文字數組中首次使用時:
MyClass>>staticInformation
| holder |
holder := #( nil ).
holder first ifNil: [ holder at: 1 put: self generateBinaryData ].
^ holder first
ifNil:
check僅在第一次執行方法時才為true,后續執行將僅返回self generateBinaryData
在第一次調用時返回的值。
一些框架暫時使用了這種模式。 但是,特別是對於二進制數據,大多數Smalltalks(包括Squeak和Pharo)現在都支持#[ … ]
形式的文字字節數組 。 然后可以簡單地將該方法寫成
MyClass>>staticInformation
^ #[42 22 4 33 4 33 11 4 33 0 0 0 0
4 33 18 4 33 4 33 9 0 14 4 33 4
33 7 4 33 0 0 9 0 7 0 0 4 33 10
4 33 4 33 7 4 33 0 0 9 0 7 0 0 4
" ... "
33 10 4 33 4 33 17 0 11 0 0 4 33
4 33 0 0 17 0 7 0 0 4 33 13 0]
過去,當某些方法將字面數組(或字符串)分發給偶然修改它的人時,它一直是一個混亂的源頭。 很難找到,因為源代碼沒有反映文字數組的內容。
因此,一些Smalltalks(VisualWorks,Smalltalk / X和其他人)使文字不可變並且在寫入文字時會引發異常(Smalltalk / X允許在編譯時關閉它,以防你確實需要該功能是為了向后兼容)。
我們一直在我們公司工作多年,我們真的不會錯過或需要可變陣列。 我敢打賭,在不久的Squeak版本中,情況也是如此(如果還沒有在隊列中或某些更改文件中)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.