簡體   English   中英

為什么我不應該存儲在Smalltalk中的文字數組中?

[英]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中的文字陣列

至少在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不同。

不同的方法

  1. 復制(始終安全)
    為了克服這個問題,您可以在使用前簡單地復制文字數組。 你的例子:

     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 

    這總是安全的,不會改變方法對象中的數組。

  2. 支撐陣列(主要是便攜式)
    雖然未在標准中定義,但大多數實現都支持這樣的支撐數組表達式:

     { 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 

(Ab)使用文字數組

實際上有時會有理由改變文字數組(或者更常見的是任何方法文字,坦率地說)。 例如,如果您有靜態信息,如圖像或二進制數據,它們根本不會更改但不會一直使用,但您不能(無論出於何種原因)使用實例或類變量,您可以將對象存儲在文字數組中首次使用時:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM