VisualWorks Cincom Smalltalk阵列初始化差异

时间:2013-09-25 01:21:45

标签: smalltalk

|temp|
temp := Array new: 5.
temp at: 1 put: 10.

没有错误。

|temp|
temp := #(1 2 3 4 5).
temp at: 1 put: 10.

给出错误

两种初始化数组的方法有什么不同?

2 个答案:

答案 0 :(得分:2)

(1 2 3 4 5)是一个不可变数组。

无法修改。

Array new:10是一个非永久数组。它可以修改。

答案 1 :(得分:0)

如其他答案中所述,#(1 2 3 4 5)会导致不可变数组,并在尝试写入时引发异常。我想我会解释引入不可变集合概念的理由。

Smalltalk将源代码编译为CompiledMethod类的实例。 CompiledMethod包含字节码(表示虚拟机要执行的指令的字节)和文字。文字是由方法引用的编译器创建的对象。

请考虑以下代码:

isSmallPrime: aNumber
    ^#(2 3 5 7 11) includes: aNumber

对象#(2 3 5 7 11)是一个在CompiledMethod中存储为文字的数组。那么问题是,如果您可以更改文字中的值,则可以有效地更改代码所执行的操作,而无需更改源代码。看看代码它似乎做了一件事,但实际上它做了别的事情。

考虑以下示例:

isSmallPrime: aNumber
    ^self smallPrimes includes: aNumber

smallPrimes
    ^#(2 3 5 7 11)

corrupt
  self smallPrimes at: 1 put: 4

如果您调用corrupt,则会将smallPrimes方法的文字数组更改为#(4 3 5 7 11)。即使源代码说smallPrimes返回#(2 3 5 7 11),它确实返回#(4 3 5 7 11),因为它被腐败的方法所破坏。随后,调用isSmallPrime:2将返回false并且isSmallPrime:4将返回true。这变得非常混乱,因为我们通常认为该方法的行为始终与源代码所说的方式相同。在这里我们有一个案例,源代码说一件事,而方法做了不同的事情。

为了防范这个问题,VisualWorks引入了不可变文字的概念。任何写入文字对象的尝试(例如在损坏的方法中)都会引发异常,以确保代码的操作与源代码所说的代码匹配。