Как работает мелкое копирование для Array в Smalltalk? - PullRequest
0 голосов
/ 11 мая 2018

Итак, насколько я понимаю, когда вы передаете сообщение 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 голосов
/ 17 мая 2018

Итак, насколько я понимаю, когда вы передаете копию сообщения в массив, выполняется поверхностная копия.Два объекта должны указывать на один и тот же массив, и теоретически, когда вы меняете один, вы меняете другой.

Это ваша ошибка.Это правда, что копия будет производить мелкую копию, но ваше представление о мелкой копии неверно.Малая копия даст вам новый экземпляр объекта, но все переменные экземпляра будут продолжать указывать на одни и те же объекты.Фактически вы создаете только один новый объект.

Если вы хотите, чтобы переменные 'a' и 'b' указывали на один и тот же объект, все, что вы делаете, это назначаете их друг другу:

b := a.

Это позволит вам изменить «b», и эти изменения также повлияют на «a».

Чтобы расширить эту концепцию, у вас есть понятие deepCopy, deepDeepCopy и т. Д. Идея этих изменений заключается в том, что онитакже создайте новые объекты для переменных экземпляра.

Технически, индексированные объекты, такие как Array, OrderedCollection, String и т. д., не используют переменные экземпляра, но концепция та же - deepCopy дублирует объекты, на которые указываетскопированный объектdeepDeepCopy перешел бы на другой уровень и дублировал бы и те объекты, на которые указывает указатель.

0 голосов
/ 18 мая 2018

Посмотрите, имеет ли это для вас смысл:

|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')
0 голосов
/ 11 мая 2018

Операция копирования действительно создает поверхностную копию массива.Это означает, что создается новый массив, который ссылается на те же объекты («содержимое»), что и исходный массив.

Когда вы изменяете свою копию с помощью 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 newFrom:, чтобы избежать изменения строкового литерала 'first'.

...