|temp|
temp := Array new: 5.
temp at: 1 put: 10.
没有错误。
|temp|
temp := #(1 2 3 4 5).
temp at: 1 put: 10.
给出错误
两种初始化数组的方式有什么区别?
|temp|
temp := Array new: 5.
temp at: 1 put: 10.
没有错误。
|temp|
temp := #(1 2 3 4 5).
temp at: 1 put: 10.
给出错误
两种初始化数组的方式有什么区别?
它不能被修改。
Array new: 10 是一个非不可变数组。它可以修改。
正如其他答案中提到的,#(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 引入了不可变文字的概念。任何写入文字对象的尝试(例如在损坏的方法中)都会引发异常,以确保代码的操作与源代码所说的代码所做的匹配。