К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как обойти структуру в цикле в 1С

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

Структура в языке 1С — это коллекция пар «ключ — значение», где ключ всегда строка, а значение может быть любого типа: числом, датой, ссылкой, другой структурой. Разработчики используют структуры для передачи параметров между процедурами, хранения настроек, подготовки данных для запросов и обмена. Поскольку у структуры нет индексов, как у массива, обходить её можно только через перебор элементов — и у этого перебора есть особенности, которые важно понимать.

Основной инструмент обхода — цикл «Для Каждого … Из … Цикл». На каждой итерации переменная цикла получает объект типа «КлючИЗначение», у которого доступны свойства «Ключ» и «Значение». Порядок обхода соответствует порядку добавления свойств в структуру, но полагаться на него в бизнес-логике не стоит — это внутренняя деталь реализации, а не гарантированный контракт.

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

Базовый синтаксис обхода структуры

Минимальный пример обхода выглядит так: создаётся структура, затем цикл перебирает все её элементы. Переменная цикла — это не значение свойства, а объект «КлючИЗначение», поэтому обращение идёт через точку.

Настройки = Новый Структура;

Настройки.Вставить("Организация", "ООО Ромашка");

Настройки.Вставить("Период", ТекущаяДата());

Настройки.Вставить("ВыводитьИтоги", Истина);

Для Каждого Элемент Из Настройки Цикл

Сообщить(Элемент.Ключ + " = " + Элемент.Значение);

КонецЦикла;

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

Если нужен только список ключей без значений, удобнее собрать их в строку или массив внутри того же цикла. Отдельного метода «ПолучитьКлючи» у структуры нет — перебор остаётся единственным способом узнать состав свойств.

Проверка наличия свойства и безопасное чтение

Обращение к несуществующему свойству структуры вызывает исключение «Поле объекта не обнаружено». Поэтому перед чтением значения, которого может не быть, используйте метод Свойство(). Он принимает имя ключа и, при необходимости, переменную, в которую будет помещено найденное значение.

ЗначениеПериод = Неопределено;

Если Настройки.Свойство("Период", ЗначениеПериод) Тогда

// свойство есть, значение в переменной ЗначениеПериод

Иначе

// свойства нет — используем значение по умолчанию

ЗначениеПериод = ТекущаяДата();

КонецЕсли;

Внутри цикла обхода проверка Свойство() обычно не нужна — все перебираемые ключи гарантированно существуют. Но она становится критичной, когда вы обходите одну структуру и читаете соответствующие ключи из другой, например при слиянии настроек или сопоставлении данных из двух источников.

Изменение структуры во время обхода: что можно и что нельзя

Частая задача — пройти по структуре и что-то в ней поменять: удалить пустые значения, переименовать ключи, добавить вычисляемые поля. Здесь кроется главная ловушка: изменять состав коллекции (добавлять или удалять свойства) во время её обхода нельзя — платформа выбросит исключение о недопустимой операции с коллекцией.

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

// Удаляем все свойства со значением Неопределено

КлючиКУдалению = Новый Массив;

Для Каждого Элемент Из Настройки Цикл

Если Элемент.Значение = Неопределено Тогда

КлючиКУдалению.Добавить(Элемент.Ключ);

КонецЕсли;

КонецЦикла;

Для Каждого Ключ Из КлючиКУдалению Цикл

Настройки.Удалить(Ключ);

КонецЦикла;

Порядок безопасного изменения структуры
  1. 1
    Пройдите структуру циклом и запишите ключи для удаления или пары для добавления во временную коллекцию
  2. 2
    Завершите цикл обхода
  3. 3
    Примените изменения отдельным циклом по временной коллекции
  4. 4
    Проверьте результат повторным обходом или отладчиком

Обход вложенных структур и рекурсия

На практике структуры часто бывают многоуровневыми: настройки отчёта, данные из JSON, параметры обмена. Для обхода такого дерева используют рекурсивную процедуру: если значение элемента — структура или соответствие, процедура вызывает сама себя для этого значения.

Процедура ОбойтиРекурсивно(Коллекция, Путь = "")

Для Каждого Элемент Из Коллекция Цикл

ТекущийПуть = ?(Путь = "", Элемент.Ключ, Путь + "." + Элемент.Ключ);

Если ТипЗнч(Элемент.Значение) = Тип("Структура")

Или ТипЗнч(Элемент.Значение) = Тип("Соответствие") Тогда

ОбойтиРекурсивно(Элемент.Значение, ТекущийПуть);

Иначе

Сообщить(ТекущийПуть + " = " + Элемент.Значение);

КонецЕсли;

КонецЦикла;

КонецПроцедуры

Накопление полного пути к свойству («Настройки.Отбор.Организация») полезно при поиске значений, логировании и построении плоского представления дерева. Учитывайте ограничение: глубина рекурсии в 1С ограничена стеком вызовов, поэтому для данных с потенциально очень глубокой вложенностью лучше использовать явный стек на массиве вместо рекурсии.

Копирование, слияние и сравнение структур

Присваивание структуры другой переменной не создаёт копию — обе переменные ссылаются на один и тот же объект. Изменение через одну переменную будет видно через другую. Чтобы получить независимую копию, создайте новую структуру и перенесите элементы циклом.

Функция СкопироватьСтруктуру(Источник)

Копия = Новый Структура;

Для Каждого Элемент Из Источник Цикл

Копия.Вставить(Элемент.Ключ, Элемент.Значение);

КонецЦикла;

Возврат Копия;

КонецФункции

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

Сравнение двух структур также выполняется обходом: перебираете первую структуру, для каждого ключа проверяете наличие во второй через Свойство() и равенство значений, затем повторяете в обратную сторону для поиска ключей, которых нет в первой. Готового метода сравнения у платформы нет.

Структура или соответствие

Структура

Ключи — допустимые идентификаторы, обращение возможно через точку (Структура.Ключ). Подходит для параметров и настроек с известным составом полей.

Соответствие

Ключи — любые строки и даже другие типы, обращение только через квадратные скобки. Подходит для произвольных справочников ключ-значение из внешних данных.

Производительность и ограничения

Обход структуры — быстрая операция, и для типовых объёмов (десятки и сотни свойств) вопрос производительности не стоит. Проблемы начинаются, когда обход выполняется внутри другого цикла, например при обработке большой таблицы значений, где для каждой строки строится и обходится структура. В таких случаях структуру лучше создать один раз до цикла и переиспользовать, очищая через повторное присваивание Новый Структура или перезапись значений.

Ещё одно ограничение: структура не сериализуется напрямую в XML или JSON средствами платформы без обхода — при записи в JSON вы фактически перебираете элементы и передаёте их записи. Метод ЗаписатьJSON умеет работать со структурами напрямую, но внутри всё равно выполняется тот же перебор, поэтому циклические ссылки (структура, содержащая саму себя через цепочку вложений) приведут к ошибке.

Типичные ошибки
01
Добавление или удаление свойств внутри цикла обхода — исключение о недопустимой операции с коллекцией
02
Обращение к Элемент.Значение как к значению свойства без учёта того, что это может быть вложенная коллекция — нечитаемый вывод или ошибка преобразования
03
Присваивание структуры новой переменной вместо копирования — изменения неожиданно видны в обоих местах
04
Чтение свойства напрямую без Свойство() при необязательных ключах — исключение «Поле объекта не обнаружено»
05
Использование структуры для ключей с пробелами и дефисами — синтаксическая ошибка, нужно соответствие

Проверка результата обхода

После написания цикла обхода убедитесь, что он делает именно то, что задумано. Самый надёжный способ — отладчик: поставьте точку останова внутри цикла и посмотрите содержимое переменной Элемент на каждой итерации. Альтернатива — временный вывод через Сообщить() с ключом и значением.

Контрольные признаки корректной работы: количество итераций равно количеству свойств структуры, все ключи выводятся без исключений, после изменений состав структуры соответствует ожиданиям. Если обход «пропускает» элементы — почти наверняка где-то внутри цикла изменяется состав коллекции.

Итог

Что важно запомнить

Обход структуры выполняется циклом «Для Каждого» через пару КлючИЗначение. Состав коллекции внутри цикла не изменяют — изменения применяют после обхода. Для необязательных ключей используют Свойство(), для копирования — явный перенос элементов, для вложенных данных — рекурсию с контролем глубины.

Частые вопросы

Можно ли обойти структуру по индексу, как массив?

Нет, у структуры нет числовых индексов и метода Получить(). Единственный способ перебора — цикл «Для Каждого». Если нужен доступ по позиции, соберите ключи в массив внутри цикла и работайте уже с массивом.

Гарантирован ли порядок обхода элементов структуры?

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

Как узнать количество свойств структуры без цикла?

Метод Количество() возвращает число свойств структуры напрямую, без обхода: Настройки.Количество(). Цикл нужен только тогда, когда требуется доступ к самим ключам и значениям.

Чем отличается обход соответствия от обхода структуры?

Синтаксис цикла идентичен — та же пара КлючИЗначение. Различия в самой коллекции: у соответствия ключи могут быть любыми значениями, а обращение к элементам возможно только через квадратные скобки, а не через точку.

Как найти значение во вложенной структуре, не зная точного пути?

Используйте рекурсивный обход с накоплением пути: процедура проверяет тип каждого значения и спускается глубже при обнаружении структуры или соответствия. Найденные совпадения собирайте в массив или таблицу значений вместе с полными путями.

Почему при выводе значения структуры в сообщение я вижу служебный текст вместо данных?

Если значением является другая структура, массив или объект, неявное преобразование в строку даёт служебное представление типа. Нужно проверить тип через ТипЗнч() и для коллекций выполнить отдельный обход, а не полагаться на автоматическое преобразование.