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