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

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

Как в 1С сравнить структуры: практические способы

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

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

Проблема в том, что встроенного метода «СравнитьСтруктуры» в платформе нет, а прямое сравнение Если Структура1 = Структура2 Тогда работает не так, как ожидается: сравниваются ссылки на объекты, а не их содержимое. Даже две структуры с одинаковым наполнением будут «не равны», потому что это разные объекты в памяти.

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

Почему прямое сравнение структур не работает

Структура — объект ссылочного типа. Когда вы пишете Структура1 = Структура2, платформа проверяет, указывают ли обе переменные на один и тот же объект. Две независимо созданные структуры с идентичными ключами и значениями этот тест не пройдут.

Структура1 = Новый Структура("Имя, Возраст", "Иван", 30);

Структура2 = Новый Структура("Имя, Возраст", "Иван", 30);

Если Структура1 = Структура2 Тогда

// Сюда выполнение не попадёт

КонецЕсли;

Отсюда следует главное правило: сравнивать нужно содержимое — набор ключей и соответствующие им значения. Причём недостаточно проверить, что все ключи первой структуры есть во второй с теми же значениями: у второй структуры могут быть дополнительные ключи, и тогда структуры не равны.

Способ 1: обход ключей с проверкой значений

Самый надёжный и универсальный вариант — функция, которая сначала сравнивает количество элементов, затем для каждого ключа первой структуры проверяет наличие ключа во второй и равенство значений. Метод Свойство() позволяет безопасно проверить наличие ключа и сразу получить значение.

Функция СтруктурыРавны(Структура1, Структура2) Экспорт

Если Структура1.Количество() <> Структура2.Количество() Тогда

Возврат Ложь;

КонецЕсли;

Для Каждого КлючЗначение Из Структура1 Цикл

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

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

Возврат Ложь;

КонецЕсли;

Если КлючЗначение.Значение <> Значение2 Тогда

Возврат Ложь;

КонецЕсли;

КонецЦикла;

Возврат Истина;

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

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

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

Рекурсивное сравнение вложенных структур

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

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

И ТипЗнч(Значение2) = Тип("Структура") Тогда

Если НЕ СтруктурыРавны(КлючЗначение.Значение, Значение2) Тогда

Возврат Ложь;

КонецЕсли;

ИначеЕсли КлючЗначение.Значение <> Значение2 Тогда

Возврат Ложь;

КонецЕсли;

Способ 2: сравнение через ЗначениеВСтрокуВнутр

Функция ЗначениеВСтрокуВнутр() сериализует значение во внутреннее строковое представление платформы. Если сериализовать обе структуры и сравнить строки, можно одной операцией проверить равенство всего содержимого, включая вложенные объекты.

Функция СтруктурыРавныБыстро(Структура1, Структура2) Экспорт

Возврат ЗначениеВСтрокуВнутр(Структура1) = ЗначениеВСтрокуВнутр(Структура2);

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

У способа есть существенные ограничения. Во-первых, ЗначениеВСтрокуВнутр доступна только на сервере (в толстом клиенте — и на клиенте), в тонком и веб-клиенте функция недоступна. Во-вторых, формат внутреннего представления не гарантирован между версиями платформы, поэтому сохранённые строки нельзя использовать для долгосрочного хранения и сравнения после обновления платформы.

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

Способ 3: сравнение через JSON

Если структуры содержат только данные, сериализуемые в JSON (примитивы, массивы, вложенные структуры), удобно преобразовать обе в JSON-строки штатными средствами платформы и сравнить их. Способ работает и на клиенте, и на сервере.

Функция СтруктураВJSON(Структура)

Запись = Новый ЗаписьJSON;

Запись.УстановитьСтроку();

ЗаписатьJSON(Запись, Структура);

Возврат Запись.Закрыть();

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

Функция СтруктурыРавныJSON(Структура1, Структура2) Экспорт

Возврат СтруктураВJSON(Структура1) = СтруктураВJSON(Структура2);

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

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

Сравнение способов: какой выбрать

КритерийОбход ключейЗначениеВСтрокуВнутрJSON
Работает на тонком клиентеДаНетДа
Вложенные структурыЧерез рекурсиюДаДа
Зависимость от порядка ключейНетВозможнаВозможна
Показывает место расхожденияДаНетНет
Ссылки и сложные объектыКорректно (по ссылке)КорректноПо представлению
Маршрут решения

Как выбрать способ

Нужна диагностика — видеть, какой ключ различаетсяИспользуйте обход ключей, при расхождении логируйте имя ключа и оба значения
Сравнение только на сервере и нужна максимально короткая записьПодойдёт ЗначениеВСтрокуВнутр
Код должен работать и на клиенте, и на сервере, данные простыеИспользуйте сравнение через JSON или обход ключей
Структуры формируются в разных местах и порядок ключей не контролируетсяТолько обход ключей — строковые способы дадут ложные различия

Поиск различий вместо простого «равно/не равно»

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

Функция РазличияСтруктур(Было, Стало) Экспорт

Различия = Новый Массив;

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

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

Если НЕ Стало.Свойство(КлючЗначение.Ключ, ЗначениеНовое) Тогда

Различия.Добавить("Удалён ключ: " + КлючЗначение.Ключ);

ИначеЕсли КлючЗначение.Значение <> ЗначениеНовое Тогда

Различия.Добавить(КлючЗначение.Ключ + ": было «"

+ КлючЗначение.Значение + "», стало «" + ЗначениеНовое + "»");

КонецЕсли;

КонецЦикла;

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

Если НЕ Было.Свойство(КлючЗначение.Ключ) Тогда

Различия.Добавить("Добавлен ключ: " + КлючЗначение.Ключ);

КонецЕсли;

КонецЦикла;

Возврат Различия;

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

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

Порядок внедрения сравнения в конфигурацию
  1. 1
    Создайте в общем модуле функцию СтруктурыРавны с обходом ключей и проверкой количества
  2. 2
    При необходимости добавьте рекурсивную обработку вложенных структур и массивов
  3. 3
    Покройте функцию проверками: одинаковые структуры, разные значения, лишний ключ, отсутствующий ключ
  4. 4
    Используйте функцию в местах, где раньше стояло сравнение через «=» или ручные проверки отдельных полей
  5. 5
    Для журналирования изменений используйте вариант с возвратом списка различий

Типичные ошибки и как их избежать

Первая и самая массовая ошибка — сравнение структур оператором «=» и уверенность, что проверяется содержимое. Такой код молча работает неправильно: условие почти всегда ложно, и логика «структуры совпали» никогда не выполняется.

Вторая ошибка — сравнение дат и чисел разных типов. Значение 0 и Ложь, число 1 и строка "1" при сравнении оператором не равны, и это корректно, но разработчик иногда ожидает «мягкого» сравнения. Если типы значений могут плавать, приводите их к ожидаемому типу перед сравнением.

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

Типичные ошибки
01
Сравнение через «=» — сравниваются ссылки, условие почти всегда ложно
02
Отсутствие проверки Количество() — лишние ключи во второй структуре остаются незамеченными
03
Использование ЗначениеВСтрокуВнутр на тонком клиенте — ошибка выполнения
04
Сравнение строк JSON при неконтролируемом порядке заполнения ключей — ложные различия
05
Сравнение вложенных структур оператором «&lt;&gt;» без рекурсии — неверный результат

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

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

При отладке расхождений в реальных данных удобно временно выводить обе структуры в сообщения или журнал регистрации через JSON-представление — так видно фактическое содержимое, а не только факт неравенства. Функция поиска различий из раздела выше решает эту задачу без дополнительного кода.

Контрольные точки

Как проверить корректность функции

Две структуры с одинаковым содержимым, созданные отдельно
Норма

Функция возвращает Истина

Тревожный признак

Возвращает Ложь — вероятно, где-то сравнение по ссылке

Во второй структуре добавлен лишний ключ
Норма

Функция возвращает Ложь

Тревожный признак

Возвращает Истина — нет проверки количества элементов

Разный порядок добавления одинаковых ключей
Норма

Обход ключей возвращает Истина

Тревожный признак

Строковые способы могут вернуть Ложь — это их ограничение

Вложенная структура с отличием внутри
Норма

Рекурсивный вариант находит различие

Тревожный признак

Простой обход с «&lt;&gt;» различие не видит

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

Можно ли сравнить структуру с фиксированной структурой?

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

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

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

Учитывается ли регистр ключей при сравнении?

Ключи структуры в 1С регистронезависимы: Свойство("Имя") и Свойство("ИМЯ") обращаются к одному ключу. Функция обхода ключей корректно сработает, даже если в двух структурах ключи заданы в разном регистре.

Что быстрее — обход ключей или сериализация?

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

Можно ли использовать СравнениеЗначений для структур?

Объект СравнениеЗначений предназначен для упорядочивания примитивных значений и не умеет сравнивать структуры по содержимому. Для структур он не подходит — используйте один из описанных способов.

Итог

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

Структуры в 1С нельзя сравнивать оператором «=» — он сравнивает ссылки. Универсальное решение — функция обхода ключей с проверкой количества элементов и рекурсией для вложенных структур. Строковые способы (ЗначениеВСтрокуВнутр, JSON) короче, но зависят от порядка ключей и места выполнения. Для аудита изменений используйте вариант, возвращающий список различий.