You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Smalltalk中Array的shallow copy工作原理及代码异常问询

Smalltalk数组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')

别急,其实你看到的现象并不是copy做了深拷贝,而是你混淆了修改数组元素引用和修改元素本身的区别。让我一步步拆解:

  1. copy确实是浅拷贝
    从运行结果里的(a at: 1) == (b at: 1)一开始返回true就能看出来——拷贝后的数组b和原数组a的初始元素是指向同一个字符串对象的。这完全符合浅拷贝的定义:新数组是一个新的容器,但容器里装的还是原来的元素引用。

  2. 为什么修改元素后看起来独立?
    你执行的b at: 1 put: 'newFirst'并不是修改了原来的字符串对象,而是把b数组的第一个位置的引用换成了一个全新的字符串对象。原数组a的第一个位置仍然指向原来的'first',所以两者自然就不一样了。

    反过来,如果数组里的元素是可变对象(比如另一个数组或者自定义的可变类实例),你去修改这个元素的内部状态,那两个数组都会看到变化。比如试试这个:

    | a b subArray |
    subArray := #('inner') asOrderedCollection.
    a := {subArray}.
    b := a copy.
    subArray add: 'changed'.
    Transcript show: a; cr.  "会显示#(('inner' 'changed'))"
    Transcript show: b; cr.  "同样显示#(('inner' 'changed'))"
    

    这时候就能看到浅拷贝的特性了——因为两个数组共享同一个子数组元素,修改子数组的内部状态会影响两者。

  3. 再看你的代码细节

    • a == b返回false:这说明a和b是两个不同的数组对象,这正是copy的作用——创建一个新的数组容器。
    • 当你执行a at: 2 put: '2nd'时,同样是给a的第二个位置换了新的字符串引用,b的第二个位置还是原来的'second',所以两者各自独立。
    • 最后把a设为nil,b依然存在,这也说明它们是两个独立的对象,只是最初共享元素引用而已。

总结一下:copy对数组做的是浅拷贝——新数组是新对象,但元素和原数组共享引用。你看到的"独立"是因为你替换了数组里的元素引用,而不是修改元素本身的状态。如果元素是可变对象,修改元素内部状态时,两个数组才会同时反映变化。

内容的提问来源于stack exchange,提问作者On The Net Again

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:12:20