Как скопировать массив в 1С: обзор всех способов и подводные камни

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

При разработке на платформе 1С:Предприятие мы регулярно работаем с различными коллекциями значений. Одной из самых частых задач является копирование данных. Проанализируем ситуацию: если мы просто присвоим массив новой переменной, платформа передаст лишь ссылку на ту же область памяти. Любое изменение в новом массиве мгновенно отразится на оригинале. Рассмотрим подробнее, как правильно создавать независимые копии массивов, разберем по шагам популярные методы и выясним причины использования тех или иных подходов в зависимости от контекста задачи.

Способ 1: Копирование через конструктор и фиксированный массив

Начнем с одного из самых элегантных и производительных способов, доступных на уровне платформы начиная с версий 8.3.3. Суть заключается в использовании промежуточного объекта — фиксированной коллекции. Посмотрим на пример кода:

КопияМассива = Новый Массив(Новый ФиксированныйМассив(МассивИсточник));

Разберем по шагам, что здесь происходит:

  1. Сначала вызывается конструктор объекта ФиксированныйМассив, в который передается наш исходный массив. Платформа "замораживает" данные.
  2. Затем вызывается конструктор обычного объекта Массив, который в качестве параметра принимает созданную на предыдущем шаге фиксированную коллекцию.
  3. Создаваемый массив заполняется значениями, при этом происходит рекурсивное преобразование: если элементами были другие фиксированные массивы, они тоже преобразуются в обычные изменяемые массивы.

Преимущества: Это один из самых быстрых способов сделать копию, так как вся работа выполняется в ядре платформы на уровне C++, избегая медленных циклов встроенного языка 1С. Более того, экспериментально доказано, что если вам нужно получить неполную копию большого массива (срез), будет быстрее скопировать его целиком этим методом, а затем удалить лишнее через Удалить, чем перебирать и добавлять нужные элементы в цикле.

Недостатки: Способ требует временного выделения оперативной памяти под промежуточный объект ФиксированныйМассив.

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

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


// Простое копирование
Копия = ОбщегоНазначенияКлиентСервер.СкопироватьМассив(МассивИсточник);

// Рекурсивное копирование (если внутри есть другие коллекции)
Копия = ОбщегоНазначения.СкопироватьРекурсивно(МассивИсточник);

Выясним причину популярности этих методов. Под капотом БСП не содержит магии: это классический перебор элементов циклом Для Каждого. Однако функция СкопироватьРекурсивно делает важную работу — она проверяет тип каждого элемента. Если внутри лежит структура, соответствие или другой массив, функция вызывает саму себя и рекурсивно копирует вложенные узлы. Это избавляет программиста от написания собственного обходчика сложных древовидных структур.

Способ 3: Использование Списка Значений (не рекомендуется)

В коде некоторых программистов можно встретить весьма нестандартный подход с применением объекта СписокЗначений. Посмотрим на пример:


СЗ = Новый СписокЗначений;
СЗ.ЗагрузитьЗначения(МассивИсточник);
МассивКопия = СЗ.ВыгрузитьЗначения();

Проанализируем этот алгоритм. Да, он работает и действительно возвращает новый массив. Однако с архитектурной точки зрения это плохая практика. Главный минус — колоссальный перерасход памяти. СписокЗначений — это сложный объект интерфейсного взаимодействия, который помимо самого значения хранит представление, пометку, картинку и другие служебные данные. Загружая массив из 100 000 элементов в список значений, вы рискуете исчерпать доступную ОЗУ на сервере. Использовать данный метод стоит только для совсем небольших коллекций, когда другие способы по какой-то причине недоступны (что крайне маловероятно).

Подводные камни: ссылочные типы и сложные объекты

Рассмотрим подробнее важнейший нюанс, о котором часто забывают. Ни один из вышеперечисленных методов (включая платформенный конструктор и рекурсию БСП) не делает глубокое копирование (абсолютный клон) ссылочных объектов БД или сложных нетиповых структур памяти, таких как ТаблицаЗначений.

Если в вашем массиве лежит таблица значений или ссылка на справочник, то после копирования в новом массиве будет лежать указатель на ту же самую таблицу и ту же самую ссылку. Если вы добавите колонку или строку в таблицу в скопированном массиве, она изменится и в оригинальном. Как быть в такой ситуации?

Способ 4: Глубокое клонирование через сериализацию

Если перед вами стоит задача создать стопроцентно независимую копию массива, внутри которого лежат таблицы значений, деревья или сложные структуры, мы применим сериализацию. Разберем по шагам этот прием:


// Вариант 1: Через внутреннюю строку (работает на сервере)
СтрокаДанных = ЗначениеВСтрокуВнутр(МассивИсточник);
АбсолютнаяКопия = ЗначениеИзСтрокиВнутр(СтрокаДанных);

// Вариант 2: Через JSON (современный подход)
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, МассивИсточник);
СтрокаJSON = ЗаписьJSON.Закрыть();

ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
АбсолютнаяКопия = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();

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

Подводя итог, можно сказать: для базовых массивов из примитивных типов оптимально использовать конструкцию через ФиксированныйМассив. Для коллекций с неизвестным или разным составом коллекций-потомков отлично подходят функции БСП. А если требуется полная независимость сложных объектов в памяти — смело используйте внутреннюю сериализацию.

← На главную