Arrays Smalltalk中数组的浅拷贝是如何工作的?

Arrays Smalltalk中数组的浅拷贝是如何工作的?,arrays,smalltalk,deep-copy,squeak,shallow-copy,Arrays,Smalltalk,Deep Copy,Squeak,Shallow Copy,因此,据我所知,当您将消息副本传递给数组时,将执行浅层复制。两个对象应该指向同一个数组,理论上,当您更改一个对象时,您也会更改另一个对象。然而,当我运行这段代码时,它的行为就像是一个深度副本。每个阵列彼此独立。我在第一个数组中进行更改,第二个数组不受影响。我在第二个数组中进行更改,第一个数组不受影响。那么,当我使用复制时,复制实际上是如何工作的呢 结果是: true false true #('first' 'second' 'third') #('newFirst' 'second' 'thi

因此,据我所知,当您将消息副本传递给数组时,将执行浅层复制。两个对象应该指向同一个数组,理论上,当您更改一个对象时,您也会更改另一个对象。然而,当我运行这段代码时,它的行为就像是一个深度副本。每个阵列彼此独立。我在第一个数组中进行更改,第二个数组不受影响。我在第二个数组中进行更改,第一个数组不受影响。那么,当我使用复制时,复制实际上是如何工作的呢

结果是:

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

复制操作确实会创建数组的浅拷贝。这意味着将创建一个新数组,该数组引用与原始数组相同的对象“内容”

通过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"
在这里,数组的副本不会更改,但原始数组及其副本的一个公共元素会更改。如果复制操作已深入,则第三行上的更改不会影响位于:1的b。它将指向另一个字符串


上面代码中的字符串newFrom:用于避免修改字符串文字“first”。

复制操作确实会创建数组的浅拷贝。这意味着将创建一个新数组,该数组引用与原始数组相同的对象“内容”

通过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"
在这里,数组的副本不会更改,但原始数组及其副本的一个公共元素会更改。如果复制操作已深入,则第三行上的更改不会影响位于:1的b。它将指向另一个字符串

上面代码中的字符串newFrom:用于避免修改字符串文字“first”

因此,据我所知,当您将消息副本传递给数组时,将执行浅层复制。两个对象应该指向同一个数组,理论上,当您更改一个对象时,您也会更改另一个对象

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

如果希望变量“a”和“b”指向同一个对象,只需将它们相互赋值:

b := a.
这将允许您修改“b”,并使更改也影响“a”

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

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

因此,据我所知,当您将消息副本传递给数组时,将执行浅层复制。两个对象应该指向同一个数组,理论上,当您更改一个对象时,您也会更改另一个对象

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

如果希望变量“a”和“b”指向同一个对象,只需将它们相互赋值:

b := a.
这将允许您修改“b”,并使更改也影响“a”

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

从技术上讲,数组、OrderedCollection、字符串等索引对象不使用实例变量,而是使用
概念相同-deepCopy复制复制对象指向的对象。DeepCopy将进入另一个深度,并复制指向对象的对象。

看看这是否对您更有意义:

|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')

看看这是否对你更有意义:

|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')