浅层复制如何在Smalltalk中使用Array?

时间:2018-05-11 06:56:06

标签: arrays smalltalk deep-copy squeak shallow-copy

因此,根据我的理解,当您将消息copy传递给数组时,会执行浅拷贝。两个对象应指向同一个数组,理论上,当您更改一个时,您将更改另一个。但是,当我运行此代码时,它就像是一个深层拷贝。每个阵列彼此独立。我在第一个数组中进行更改,第二个数组不受影响。我在第二个数组中进行更改,第一个数组不受影响。那么当我使用copy时,复制是如何实际工作的?

| a b |

a := #('first' 'second' 'third').
b := a copy.
Transcript show: a = b;cr.
Transcript show: a == b;cr.
Transcript show: (a at: 1) == (b at: 1);cr.
b at: 1 put: 'newFirst'.
Transcript show: a;cr.
Transcript show: b;cr.
Transcript show: (a at: 1) == (b at: 1);cr.
a at: 2 put: '2nd'.
Transcript show: a;cr.
Transcript show: b;cr.
a := nil.
Transcript show: a;cr.
Transcript show: b;cr.

结果是:

true
false
true
#('first' 'second' 'third')
#('newFirst' 'second' 'third')
false
#('first' '2nd' 'third')
#('newFirst' 'second' 'third')
nil
#('newFirst' 'second' 'third')

3 个答案:

答案 0 :(得分:4)

复制操作确实会创建数组的浅表副本。这意味着创建了一个新数组,它引用与原始数组相同的对象(“内容”)。

当您通过at:put:更改副本时,原始数组不会受到影响,因为其引用不会更改。此外,更改副本的引用不会改变包含的对象本身。相反,该副本现在只是引用其他对象(在您的情况下为'newFirst''2nd')。这就是为什么原始数组的内容不受新对象放入副本的影响的另一个原因。

但是,由于这是浅拷贝,因此不会复制原始数组中的字符串。您可以按如下方式观察:

a := Array with: (String newFrom: 'first') with: 'second' with: 'third'.
b := a copy.
(a at: 1) replaceFrom: 1 to: 5 with: '1st  '.  "in-place modification"
Transcript show: a = b; cr. "true"
Transcript show: (a at: 1); cr. "1st  "
Transcript show: (b at: 1); cr. "1st  "
Transcript show: (a at: 1) == (b at: 1); cr. "true"

这里,数组的副本没有改变,但原始数组的一个常见元素及其副本被更改。如果复制操作很深,b at: 1不会受到第三行更改的影响。它会指向不同的String。

上面代码中的String newFrom:是为了避免首先修改字符串文字。

答案 1 :(得分:1)

  

因此,根据我的理解,当您将消息副本传递给数组时,将执行浅拷贝。两个对象应指向同一个数组,理论上,当您更改一个时,您将更改另一个。

这是你的错。确实,副本会生成浅拷贝,但是您对浅拷贝的理解是错误的。浅拷贝将为您提供对象的新实例,但所有实例变量将继续指向相同的对象。实际上,您只创建一个新对象。

如果你想要变量' a'和' b'指向同一个对象你所做的就是将它们分配给彼此:

b := a.

这将允许您修改' b'并且更改也会影响' a'。

为了进一步扩展这个概念,你有了deepCopy和deepDeepCopy等的概念。这些变化背后的想法是它们也为实例变量创建新对象。

从技术上讲,像Array,OrderedCollection,String等索引对象不使用实例变量,但概念是相同的 - deepCopy复制复制对象指向的对象。 deepDeepCopy将深入到另一个级别并复制那些指向的对象。

答案 2 :(得分:1)

看看这对你更有意义:

|a b|
a := #('first' 'second' 'third').
b := a copy.
(b at: 1) at: 1 put: $X.
a at: 2 put: '2nd'.
Transcript show: a; cr.
Transcript show: b; cr.

...产生以下输出:

#('Xirst' '2nd' 'third')
#('Xirst' 'second' 'third')