繁体   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