Два имени могут указывать на один массив
Представим переменную с массивом, который содержит изменяемую строку со словом чай. Если другой переменной присвоить этот массив обычным присваиванием, новый независимый массив не появится. Обе переменные будут ссылаться на тот же объект. Добавление элемента через любую из них изменит общий контейнер. Полезно мысленно рисовать отдельно имена и объекты. Переменная — не коробка, в которую автоматически положили полную копию всех данных. В нашей схеме два имени ведут стрелками к одному массиву. Если позднее одно имя связать с совершенно другим массивом, это уже изменение привязки переменной, а не редактирование прежнего контейнера.
Поверхностная копия отделяет только верхний уровень
Метод dup для обычного массива создаёт отдельный массив с теми же ссылками на элементы. Теперь добавление нового элемента в копию не добавит его в исходный контейнер. Но существующая изменяемая строка может по-прежнему быть одним общим объектом, на который указывают оба массива. Поэтому изменение содержимого этой строки будет видно через обе структуры. Это и означает поверхностное копирование: внешний контейнер новый, вложенные объекты не обязательно новые. Для вложенного массива действует похожая логика. Не стоит считать слово копия доказательством полной независимости всех уровней данных.
Замена элемента и изменение элемента различаются
Если в одной копии заменить первый элемент ссылкой на новую строку, это меняет соответствующую ячейку именно этого массива. Если же взять существующую общую строку и изменить её содержимое, результат увидят все ссылки на неё. Эти операции могут выглядеть похожими по конечному тексту, но затрагивают разные объекты. В реальном коде сначала выясните, какой уровень должен быть независимым. Для простого массива отдельных изменяемых строк может потребоваться копирование и контейнера, и каждой строки. У более сложной структуры есть дополнительные вопросы: общие вложенные объекты, циклические ссылки и поведение пользовательских классов. Универсально заменять dup на другой метод без понимания структуры недостаточно.
Попробуйте на практике
Нарисуйте схему обычных массивов и изменяемых строк. Все действия выполняются на бумаге; речь идёт именно об изменении объектов, а не о замороженных строках.
- Изобразите один массив с единственной строкой чай. Проведите к массиву стрелки от двух разных имён: это обычное присваивание без создания копии.
- Добавьте третий объект — поверхностную копию массива. Покажите, что её первый элемент указывает на ту же строку чай.
- Через одно из первых двух имён добавьте в исходный массив новую строку кофе. Отметьте количество элементов у общего массива и у поверхностной копии.
- Измените содержимое общей первой строки с чай на сок, не заменяя ссылку в ячейке. Проследите, где теперь виден новый текст и какие размеры массивов сохранились.
Как проверить результат. Первые два имени по-прежнему указывают на массив из двух элементов, копия содержит один элемент. Во всех трёх случаях первая строка показывает сок, потому что изменён общий строковый объект.
Частые вопросы
Если напечатанное содержимое двух массивов одинаковое, это один объект?
Не обязательно. Разные массивы могут содержать равные данные. Равенство содержимого и тождественность объекта — разные вопросы. При анализе изменений нужно понимать, какие именно объекты разделяются.
Всегда ли нужно глубоко копировать данные?
Нет. Общие объекты могут быть намеренной частью решения, а неизменяемые данные упрощают совместное использование. Сначала определите, что разрешено менять и кому принадлежит изменение. Копирование должно соответствовать этой задаче, а не выполняться автоматически.
Самостоятельный разбор темы. Содержание конкретной обучающей программы здесь не представлено.