Разработка и Конфигурация · 11 мин
Как скопировать массив в 1С
Как правильно скопировать массив в 1С: оператор присваивания, цикл, Скопировать() и сериализация. Разбираем поверхностное и глубокое копирование с примерами кода.
Присваивание переменной НовыйМассив = СтарыйМассив; не создаёт копию массива в 1С — обе переменные начинают ссылаться на один и тот же объект в памяти. Изменение элемента через одну переменную немедленно отразится на другой. Это одна из самых частых причин трудноуловимых ошибок в коде, особенно когда массив передаётся между процедурами или хранится в реквизитах формы.
Реальная копия создаётся только явно: перебором элементов с добавлением в новый массив, универсальным методом через сериализацию значения или типовыми функциями из общих модулей. Выбор способа зависит от того, что лежит внутри массива — примитивные значения (числа, строки, даты) или ссылочные объекты (элементы справочников, структуры, другие массивы).
Ниже разобраны рабочие способы копирования, разница между поверхностной и глубокой копией, типичные ошибки и способы проверить, что копия действительно независима от оригинала.
Почему присваивание не копирует массив
Массив в 1С — ссылочный тип данных. Переменная хранит не сами элементы, а указатель на область памяти, где находится массив. Когда вы пишете Массив2 = Массив1;, платформа копирует только указатель. В результате обе переменные работают с одним набором элементов.
Наглядный признак проблемы: вы добавляете элемент в «копию», а он появляется и в исходном массиве. Или очищаете один массив методом Очистить() — и пустеет второй. В отладчике это видно по совпадающему представлению значения у обеих переменных.
Важно понимать: та же логика действует для структур, соответствий, таблиц значений (у таблицы есть метод Скопировать()) и списков значений. Примитивные типы — число, строка, дата, булево — при присваивании копируются по значению, поэтому с ними такой проблемы нет.
Способ 1. Копирование перебором элементов в цикле
Самый прозрачный и контролируемый способ — создать новый массив и добавить в него все элементы исходного. Это даёт поверхностную копию, которой достаточно в большинстве прикладных задач.
ИсходныйМассив = Новый Массив;
ИсходныйМассив.Добавить("Первый");
ИсходныйМассив.Добавить("Второй");
Копия = Новый Массив;
Для Каждого Элемент Из ИсходныйМассив Цикл
Копия.Добавить(Элемент);
КонецЦикла;
После такого копирования Копия.Добавить("Третий") или Копия.Очистить() никак не затронут исходный массив. Способ хорош ещё и тем, что позволяет попутно фильтровать или преобразовывать элементы — например, пропускать пустые значения или добавлять только уникальные.
Учтите ограничение: если элементы массива — структуры или другие массивы, в копию попадут ссылки на те же вложенные объекты. Изменение вложенной структуры через копию изменит её и в оригинале. Для таких случаев нужна глубокая копия.
- 1Создайте пустой массив: Копия = Новый Массив;
- 2Переберите исходный массив циклом Для Каждого
- 3Добавьте каждый элемент в копию методом Добавить()
- 4Проверьте независимость: измените копию и убедитесь, что оригинал не изменился
Способ 2. Глубокое копирование через сериализацию
Когда внутри массива лежат структуры, соответствия или другие массивы, нужна глубокая копия. Универсальный приём — сериализация значения во внутреннюю строку и обратное восстановление:
Функция СкопироватьКоллекцию(Источник)
Возврат ЗначениеИзСтрокиВнутр(ЗначениеВСтрокуВнутр(Источник));
КонецФункции
Функция ЗначениеВСтрокуВнутр преобразует значение в строковое представление внутреннего формата, а ЗначениеИзСтрокиВнутр восстанавливает из него полностью независимый объект со всеми вложенными коллекциями. Приём работает для массивов, структур, соответствий, таблиц значений и их комбинаций.
Ограничения важно учитывать заранее. Сериализуются не все типы: например, значения, привязанные к контексту формы или содержащие несериализуемые объекты, могут вызвать ошибку. Ссылки на объекты базы данных (справочники, документы) сериализуются как ссылки — после восстановления они указывают на те же записи базы, что обычно и требуется. Сама операция не бесплатна по производительности: для больших массивов в цикле с тысячами итераций лучше искать алгоритмическое решение без постоянного копирования.
Способ 3. Типовые функции общих модулей
В конфигурациях на базе Библиотеки стандартных подсистем есть готовые механизмы копирования коллекций. В актуальных релизах используется функция ОбщегоНазначения.СкопироватьРекурсивно — она создаёт глубокую копию структуры, соответствия, массива или таблицы значений с учётом вложенности.
Копия = ОбщегоНазначения.СкопироватьРекурсивно(ИсходныйМассив);
Преимущество типовой функции — она уже обрабатывает краевые случаи и проверена на множестве сценариев. Если конфигурация не на БСП, имеет смысл написать собственную рекурсивную функцию: для массива — перебор с копированием каждого элемента, для структуры и соответствия — перебор ключей с рекурсивным вызовом для значений.
Сравнение способов копирования
Подходит для плоских массивов примитивов и ссылок. Быстро, наглядно, но не копирует вложенные коллекции.
Глубокая копия почти любых коллекций. Медленнее, есть ограничения по сериализуемым типам.
Типовое решение в конфигурациях на БСП. Универсально, но требует наличия библиотеки в конфигурации.
Как выбрать способ под свою задачу
Критерий выбора простой: посмотрите, что лежит в массиве и что вы собираетесь делать с копией. Если массив содержит числа, строки, даты или ссылки на объекты базы, а вложенных коллекций нет — достаточно цикла с Добавить(). Ссылки на элементы справочников и документов копировать глубоко не нужно: это указатели на записи базы, и обе копии массива закономерно будут ссылаться на одни и те же документы.
Если внутри массива — структуры с параметрами, которые вы планируете менять независимо (например, массив настроек для нескольких потоков обработки), нужна глубокая копия через сериализацию или рекурсивную функцию. Иначе изменение настройки в одной ветке алгоритма неожиданно повлияет на другую.
Как выбрать действие
Проверка результата и типичные ошибки
Проверить независимость копии просто: после копирования добавьте в копию новый элемент или очистите её, затем сравните количество элементов в обоих массивах. Если ИсходныйМассив.Количество() не изменилось — копия независима. Для глубокой копии дополнительно измените значение во вложенной структуре копии и убедитесь, что в оригинале оно прежнее.
Как проверить результат
У оригинала количество прежнее
Оригинал изменился вместе с копией — копирования не было
Изменение вложенных значений не затрагивает оригинал
Вложенные данные общие — сделана только поверхностная копия
Процедура меняет свою копию, вызывающий код видит исходный массив
Изменения внутри процедуры видны снаружи — массив передан по ссылке
Отдельно помните о передаче массива в процедуры и функции. По умолчанию параметры передаются по ссылке: если внутри процедуры вы измените полученный массив, изменится и массив вызывающего кода. Если побочный эффект нежелателен, скопируйте массив в начале процедуры или объявите параметр с Знач — но учтите, что Знач для массива в ряде версий платформы не делает полную копию автоматически, надёжнее скопировать явно.
Во многих задачах копию можно не делать вовсе: если массив нужен один раз для обхода, а исходный дальше не используется, работайте с оригиналом. Прежде чем внедрять глубокое копирование, проверьте, нельзя ли перестроить алгоритм так, чтобы каждая ветка логики формировала собственный массив с нуля.
Итог и частые вопросы
Ключевое правило одно: массив в 1С копируется только явно. Для плоских массивов достаточно цикла с Добавить(), для вложенных структур — сериализации или рекурсивной функции. Всегда проверяйте результат изменением копии и контролем оригинала, особенно при передаче массивов между процедурами.
Что важно запомнить
Присваивание создаёт вторую ссылку на тот же массив, а не копию. Плоский массив копируйте циклом, вложенные коллекции — через ЗначениеВСтрокуВнутр/ЗначениеИзСтрокиВнутр или типовую рекурсивную функцию. После копирования проверяйте независимость изменением копии.
Почему после «копирования» оба массива меняются одновременно?
Потому что оператор присваивания копирует ссылку, а не данные. Обе переменные указывают на один объект в памяти. Создайте новый массив и перенесите элементы циклом — тогда изменения станут независимыми.
Как скопировать массив структур, чтобы они были полностью независимы?
Нужна глубокая копия: используйте связку ЗначениеВСтрокуВнутр и ЗначениеИзСтрокиВнутр либо рекурсивную функцию, которая копирует каждую структуру и каждое вложенное значение. Простой цикл скопирует только ссылки на те же структуры.
Есть ли у массива встроенный метод Копировать(), как у таблицы значений?
Нет, у объекта «Массив» встроенного метода копирования нет — в отличие от таблицы значений со её методом Скопировать(). Копию массива создают вручную циклом или через сериализацию.
Нужно ли копировать массив, если в нём лежат ссылки на документы?
Сам массив — да, если планируете менять его состав независимо (добавлять, удалять элементы). А вот глубоко копировать сами ссылки не нужно: это указатели на записи базы данных, и обе копии массива корректно ссылаются на одни и те же документы.
Что быстрее: цикл или сериализация?
Для плоских массивов цикл с Добавить() заметно легче по ресурсам. Сериализация оправдана только когда нужна глубокая копия вложенных коллекций. В массовых обработках любое копирование внутри цикла стоит минимизировать.
Как передать массив в процедуру, чтобы она его не испортила?
Скопируйте массив в начале процедуры в локальную переменную и работайте с копией. Параметры по умолчанию передаются по ссылке, поэтому изменение параметра внутри процедуры затрагивает массив вызывающего кода.