При разработке алгоритмов на платформе 1С:Предприятие часто возникает задача обхода одной коллекции и формирования на ее основе массива структур. Начинающие разработчики нередко сталкиваются с ситуацией, когда после завершения цикла все элементы результирующего массива содержат одинаковые данные — значение последней итерации. Разберем по шагам, почему возникает такое поведение платформы и как правильно организовать заполнение массива.
Проанализируем исходную ситуацию. Предположим, у нас есть коллекция Соответствие, данные из которой мы переносим в массив Компенсации, входящий в состав структуры ОписаниеНачислений:
Компенсация = Новый Соответствие;
Компенсация.Вставить("Работа в ночное время", "В размере 100% от часовой тарифной ставки");
Компенсация.Вставить("Работа в вечернее время", "В размере 20% от часовой тарифной ставки");
Компенсация.Вставить("Работа в праздничные дни", "В размере 100% от часовой тарифной ставки");
Для Каждого СЧТ Из Компенсация Цикл
ОписаниеНачисления.Начисление = СЧТ.Ключ;
ОписаниеНачисления.Размер = СЧТ.Значение;
ОписаниеНачислений.Компенсации.Добавить(ОписаниеНачисления);
КонецЦикла;
В результате выполнения этого фрагмента кода в массиве действительно окажется три элемента, однако все они будут содержать значения последней итерации («Работа в праздничные дни»). Выясним причину такого поведения.
В платформе 1С:Предприятие все типы данных разделяются на две группы:
Число, Строка, Дата, Булево, Неопределено, Null) — копируются и передаются исключительно по значению. При присваивании переменной создается отдельная независимая копия данных.Структура, Массив, Соответствие, ТаблицаЗначений, СписокЗначений и др.) — хранятся в памяти как единый экземпляр объекта. Переменные, содержащие такие типы, хранят не сами данные, а ссылку (указатель) на область памяти.Когда мы инициализируем объект ОписаниеНачисления до входа в цикл и затем вызываем метод Добавить(ОписаниеНачисления), в массив помещается не копия структуры, а ссылка на один и тот же объект в оперативной памяти. На каждой следующей итерации цикла свойства этого единственного объекта перезаписываются. Поскольку все элементы массива ссылаются на одну и ту же область памяти, при чтении любого элемента массива мы видим самые последние записанные значения.
Самый простой и наглядный способ устранения ошибки — создавать новый экземпляр структуры на каждой итерации цикла. В этом случае для каждого шага будет выделяться отдельная область памяти, и массив будет хранить ссылки на уникальные объекты.
Посмотрим на исправленный вариант кода:
Для Каждого СЧТ Из Компенсация Цикл
// На каждом шаге создаем абсолютно новый объект
ОписаниеНачисления = Новый Структура;
ОписаниеНачисления.Вставить("Начисление", СЧТ.Ключ);
ОписаниеНачисления.Вставить("Размер", СЧТ.Значение);
ОписаниеНачислений.Компенсации.Добавить(ОписаниеНачисления);
КонецЦикла;
Теперь на каждой итерации переменная ОписаниеНачисления указывает на новый экземпляр, и изменение данных на следующем шаге никак не затрагивает уже добавленные в массив структуры.
Рассмотрим более компактный и профессиональный синтаксис платформы 1С:Предприятие. Конструктор объекта Структура позволяет одновременно объявить имена свойств и передать их значения через запятую в одну строку.
Разберем пример:
Для Каждого СЧТ Из Компенсация Цикл
// Создаем структуру и сразу передаем ее в массив
ОписаниеНачислений.Компенсации.Добавить(
Новый Структура("Начисление, Размер", СЧТ.Ключ, СЧТ.Значение)
);
КонецЦикла;
Преимущества такого подхода:
Если у вас уже есть базовая структура с предопределенным набором полей или значений по умолчанию, можно воспользоваться конструктором копирования или процедурой ЗаполнитьЗначенияСвойств.
Рассмотрим создание независимой копии структуры:
БазоваяСтруктура = Новый Структура("Начисление, Размер, Дополнительно", "", "", "По умолчанию");
Для Каждого СЧТ Из Компенсация Цикл
// Создаем копию структуры на основе шаблона
НоваяСтруктура = Новый Структура(БазоваяСтруктура);
НоваяСтруктура.Начисление = СЧТ.Ключ;
НоваяСтруктура.Размер = СЧТ.Значение;
ОписаниеНачислений.Компенсации.Добавить(НоваяСтруктура);
КонецЦикла;
Важное замечание: конструктор копирования Новый Структура(Шаблон) выполняет поверхностное копирование (Shallow Copy). Если свойства исходной структуры содержат другие коллекции (вложенные массивы или таблицы), они останутся общими ссылками. Если требуется глубокое клонирование всего графа объектов, на стороне сервера применяют сериализацию через ЗначениеИзСтрокиВнутр(ЗначениеВСтрокуВнутр(Объект)) или механизмы XDTO/JSON.
Разберем еще один смежный нюанс, с которым сталкиваются разработчики при передаче коллекций в процедуры и функции. Даже если параметр процедуры объявлен с ключевым словом Знач, передача ссылочного типа (структуры или массива) защищает только саму переменную от переопределения ссылки, но не защищает ее внутренние свойства от модификации.
Для защиты данных от случайных изменений после формирования коллекции в платформе 1С предусмотрены специальные неизменяемые типы: ФиксированнаяСтруктура, ФиксированныйМассив и ФиксированноеСоответствие. Если после заполнения массива зафиксировать коллекцию, любая попытка изменить ее состав или свойства вызовет исключение времени выполнения, что гарантирует целостность переданных данных.