Как правильно скопировать массив в 1С, чтобы изменения в копии не влияли на оригинал?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С:Предприятие начинающие (а иногда и опытные) программисты сталкиваются с неожиданным поведением массивов при попытке их копирования. Типичная ситуация: мы создаем Массив1, наполняем его данными, затем пишем Массив2 = Массив1, ожидая получить независимую копию. Однако, удалив элемент из Массив2, мы обнаруживаем, что он исчез и из Массив1. В этой статье мы подробно разберем, почему так происходит, и изучим все надежные способы создания полноценной копии массива. Для этого есть инструмент пошаговой отладки кода 1С.

Выясним причину: почему оператор «равно» не копирует массив?

Проанализируем ситуацию с точки зрения устройства памяти. В 1С все типы данных делятся на примитивные (число, строка, дата, булево) и ссылочные (массивы, структуры, таблицы значений, ссылки на объекты базы данных). Когда мы работаем с числом, переменная хранит само значение. Когда мы работаем с массивом, переменная хранит лишь адрес в оперативной памяти, по которому этот массив располагается.

Рассмотрим, что происходит при выполнении кода Массив2 = Массив1:

  1. Программа обращается к переменной Массив1 и считывает адрес области памяти.
  2. Этот адрес записывается в переменную Массив2.
  3. В итоге обе переменные указывают на один и тот же блок ячеек в памяти.

Именно поэтому любое «страшное» действие над вторым массивом (удаление, добавление, изменение элементов) мгновенно отражается на первом — по сути, вы работаете с одним и тем же объектом под разными именами. Чтобы получить независимый объект, нам нужно выделить новую область памяти и заполнить ее данными. Разберем, как это сделать.

Способ 1: Использование промежуточного фиксированного массива

Это один из самых изящных и быстрых способов, реализованных на уровне платформы. Мы воспользуемся конструкторами объектов ФиксированныйМассив и Массив. Рассмотрим по шагам:


// Исходный массив
МассивПолный = Новый Массив;
МассивПолный.Добавить(10);
МассивПолный.Добавить(20);

// Создаем копию через промежуточное преобразование
Фиксированный = Новый ФиксированныйМассив(МассивПолный);
МассивКопия = Новый Массив(Фиксированный);

// Теперь это разные объекты
МассивКопия.Удалить(0); 
// В МассивКопия остался один элемент, в МассивПолный — по-прежнему два

Этот метод работает быстро, так как конструктор ФиксированныйМассив создает внутреннюю копию данных, а последующее создание обычного массива из фиксированного снова копирует эти данные в новый динамический объект.

Способ 2: Ручной перебор элементов (универсальный метод)

Если нам нужно не просто скопировать массив, а выполнить при этом какую-то фильтрацию или если мы хотим полностью контролировать процесс, используем цикл Для каждого. Посмотрим на пример кода, который позволяет создать «чистую» копию: решается через консоль кода для тестирования алгоритмов 1С.


МассивИсточник = Новый Массив;
// ... заполнение источника ...

МассивПриемник = Новый Массив;
Для каждого Элемент Из МассивИсточник Цикл
    МассивПриемник.Добавить(Элемент);
КонецЦикла;

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

Способ 3: Использование функций Библиотеки Стандартных Подсистем (БСП)

Если ваша конфигурация построена на базе БСП (а это почти все современные типовые решения), нет смысла «изобретать велосипед». В общем модуле ОбщегоНазначения (или ОбщегоНазначенияКлиентСервер) есть готовые инструменты. Проанализируем возможности:

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

Способ 4: «Хакерский» метод через сериализацию (Глубокое копирование)

Если нам нужно гарантированно разорвать все связи между объектами (включая вложенные структуры внутри массива) без использования БСП, можно применить метод сериализации через временное хранилище. Рассмотрим этот прием:


// Помещаем массив в хранилище (происходит сериализация в байты)
АдресХранилища = ПоместитьВоВременноеХранилище(ОригиналМассива);

// Получаем обратно (создается абсолютно новый объект со всеми вложенными данными)
ГлубокаяКопия = ПолучитьИзВременногоХранилища(АдресХранилища);

Этот способ работает медленнее циклов, так как требует затрат на сериализацию, но он незаменим, когда массив имеет сложную вложенную структуру и нам нужно полное клонирование.

Почему сравнение массивов через «=» всегда возвращает Ложь?

Разберем еще один нюанс, который часто путает разработчиков. Посмотрим на код:


Массив1 = Новый Массив;
Массив2 = Новый Массив;
Сообщить(Массив1 = Массив2); // Результат: Ложь

Даже если оба массива абсолютно пусты или содержат идентичные наборы чисел, оператор сравнения = вернет Ложь. Это происходит потому, что для сложных объектов 1С сравнивает не содержимое, а идентичность ссылок. Поскольку Массив1 и Массив2 были созданы двумя разными вызовами оператора Новый, они занимают разные адреса в памяти. Для системы это разные сущности, даже если они выглядят одинаково.

Резюмируем:

  1. Никогда не используйте Массив2 = Массив1, если планируете изменять данные в одном из них независимо.
  2. Для быстрой поверхностной копии используйте связку с ФиксированныйМассив.
  3. Для сложной вложенной структуры используйте рекурсивные функции БСП или метод с временным хранилищем.
  4. Помните, что циклом Для каждого можно не только скопировать, но и сразу отфильтровать ненужные элементы.
← На главную