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

没有错误。

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

给出错误

两种初始化数组的方式有什么区别?

4

2 回答 2

2

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

它不能被修改。

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

于 2013-09-25T03:56:45.947 回答
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

如果调用损坏,则将 smallPrimes 方法的文字数组更改为 #(4 3 5 7 11)。尽管源代码说 smallPrimes 返回 #(2 3 5 7 11) 它实际上返回 #(4 3 5 7 11) 因为它被损坏的方法破坏了。随后,调用 isSmallPrime: 2 将返回 false 并且 isSmallPrime: 4 返回 true。这变得非常混乱,因为我们通常假设该方法总是按照源代码所说的方式运行。在这里,我们有一个案例,源代码说一件事,而方法做另一件事。

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

于 2013-09-26T23:40:23.573 回答