Сравнение данных в 1С:Предприятие — одна из самых частых операций, с которой сталкиваются разработчики. На первый взгляд кажется, что всё просто: достаточно поставить оператор = или <>, и платформа сама разберётся. Но на практике даже опытные программисты сталкиваются с неожиданными результатами при сравнении ссылок на объекты, значений NULL, коллекций или примитивных типов разных форм. Например, почему Число(10) = 10 возвращает Истина, а Строка("10") = 10Ложь? Или как правильно проверить, что две ссылки указывают на один и тот же документ, а не просто имеют одинаковые реквизиты?

В этой статье мы разберём все нюансы сравнения типов данных в 1С, включая скрытые особенности операторов, функции СравнитьЗначения() и ТипЗнч(), а также типичные ошибки, которые приводят к багам в коде. Вы узнаете, как платформа преобразует типы при сравнении, почему иногда лучше использовать ПолноеСравнение(), и как избежать ловушек с Неопределено и NULL. Материал будет полезен как начинающим разработчикам, так и опытным специалистам, которые хотят систематизировать знания.

1. Базовые операторы сравнения: ==, <>, >, <

В для сравнения значений используются стандартные операторы: = (или ==), <>, <, <=, >, >=. На первый взгляд они работают предсказуемо, но есть важные нюансы:

  • 🔹 Оператор = выполняет нестрогое сравнение с автоматическим приведением типов. Например, Число(10) = "10" вернёт Истина, потому что строка будет преобразована в число.
  • 🔹 Для строгого сравнения (без приведения типов) используйте функцию СравнитьЗначения() или оператор === (в последних версиях платформы).
  • 🔹 Операторы < и > работают только с примитивными типами (числа, строки, даты). Для объектов они вызовут ошибку.

Пример неочевидного поведения:

Сообщить(10 = "10");       // Истина (строка преобразована в число)

Сообщить(10 === "10"); // Ошибка: несовместимые типы для строгого сравнения

Сообщить(СравнитьЗначения(10, "10")); // Ложь (типы не совпадают)

⚠️ Внимание: При сравнении чисел в формате с плавающей точкой (например, 0.1 + 0.2) могут возникать погрешности из-за особенностей хранения дробных чисел. Для финансовых расчётов используйте тип Число(15, 2) и функцию Окр().
📊 Какой оператор сравнения вы используете чаще всего?
== (нестрогое)
=== (строгое)
СравнитьЗначения()
Зависит от задачи

2. Сравнение примитивных типов: числа, строки, даты

Примитивные типы (Число, Строка, Дата, Булево) сравниваются по значению, но с учётом правил приведения типов. Рассмотрим ключевые моменты:

  • 📌 Числа: Сравниваются математически. Осторожно с Неопределено — любое сравнение с ним вернёт Ложь, кроме проверки на ТипЗнч(Значение) = Тип("Неопределено").
  • 📌 Строки: Сравниваются посимвольно с учётом регистра. Для безрегистрового сравнения используйте НРег() или СравнитьСтроки().
  • 📌 Даты: Сравниваются как числовые значения (количество секунд с 01.01.0001). Например, Дата(2026,1,1) > Дата(2026,12,31) вернёт Истина.

Особенности строкового сравнения:

Сообщить("А" > "а"); // Ложь (коды символов: 'А'=192, 'а'=224)

Сообщить(СравнитьСтроки("А", "а", Ложь)); // 0 (без учёта регистра)

Тип данныхОператор =Функция СравнитьЗначения()Примечание
Число vs ЧислоСравнивает значенияСравнивает значенияПогрешности при дробных числах
Число vs СтрокаПреобразует строку в числоВернёт ЛожьОпасно для нечисловых строк
Строка vs СтрокаПосимвольно с регистромТо же, что и =Используйте НРег() для игнорирования регистра
Дата vs ДатаСравнивает временные меткиТо же, что и =Точность до секунды
Если НачалоДня(Дата1) = НачалоДня(Дата2) Тогда...-->

3. Сравнение ссылок на объекты: документы, справочники, планы видов характеристик

Ссылки на объекты (ДокументОбъект, СправочникОбъект и др.) сравниваются по идентификатору, а не по содержимому реквизитов. Это означает, что две ссылки считаются равными, только если они указывают на один и тот же объект в базе данных.

Ключевые правила:

  • 🔗 Ссылка1 = Ссылка2 возвращает Истина, если обе ссылки указывают на один объект (даже если реквизиты разные).
  • 🔗 Сравнение Ссылка = Неопределено вернёт Истина, только если ссылка пустая.
  • 🔗 Для сравнения реквизитов объектов нужно явно обращаться к полям: Ссылка1.Номер = Ссылка2.Номер.

Пример:

Док1 = Документы.ЗаказПокупателя.НайтиПоНомеру("0001");

Док2 = Документы.ЗаказПокупателя.НайтиПоНомеру("0001");

// Сравнение ссылок (одинаковые объекты)

Сообщить(Док1 = Док2); // Истина

// Сравнение реквизитов

Сообщить(Док1.СуммаДокумента = Док2.СуммаДокумента); // Зависит от содержимого

⚠️ Внимание: Если вы сравниваете ссылки из разных баз данных (например, при обмене данными), используйте УникальныйИдентификатор(): Если Ссылка1.УникальныйИдентификатор() = Ссылка2.УникальныйИдентификатор() Тогда...

4. Сравнение с NULL и Неопределено: ловушки и решения

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

  • 🚫 Значение = NULL всегда возвращает Ложь, даже если Значение действительно NULL.
  • ✅ Для проверки на NULL используйте Значение Есть NULL или Значение = Тип("NULL").
  • 🚫 Неопределено = Неопределено возвращает Истина, но Неопределено = ЛюбоеДругоеЗначение — всегда Ложь.

Правильные способы проверки:

// Проверка на NULL

Если Значение Есть NULL Тогда

Сообщить("Это NULL");

КонецЕсли;

// Проверка на Неопределено

Если ТипЗнч(Значение) = Тип("Неопределено") Тогда

Сообщить("Значение не определено");

КонецЕсли;

Значение= NULLЕсть NULLТипЗнч() = Тип("NULL")
NULLЛожьИстинаИстина
НеопределеноЛожьЛожьЛожь
Пустая строка ""ЛожьЛожьЛожь
Число 0ЛожьЛожьЛожь
Почему Значение = NULL всегда возвращает Ложь?

В языке 1С оператор = не предназначен для сравнения с NULL — это архитектурное ограничение платформы. Для проверки на NULL используйте конструкцию Есть NULL, которая работает на уровне SQL-запросов.

5. Сравнение коллекций: массивы, структуры, соответствия

Коллекции (Массив, Структура, Соответствие) сравниваются по ссылке, а не по содержимому. Это означает, что две коллекции с одинаковыми данными не будут равны, если это разные объекты в памяти.

Как правильно сравнивать коллекции:

  • 📦 Для массивов используйте СравнитьМассивы() (побитовое сравнение элементов).
  • 📦 Для структур и соответствий сравнивайте ключи и значения в цикле или используйте ПолноеСравнение() (доступно в последних версиях платформы).
  • 📦 Оператор = для коллекций сравнивает только ссылки, а не содержимое!

Примеры:

Массив1 = Новый Массив;

Массив1.Добавить(1);

Массив1.Добавить(2);

Массив2 = Новый Массив;

Массив2.Добавить(1);

Массив2.Добавить(2);

Сообщить(Массив1 = Массив2); // Ложь (разные объекты)

Сообщить(СравнитьМассивы(Массив1, Массив2)); // Истина (содержимое одинаково)

Сравнить количество ключей с помощью Структура1.Количество() = Структура2.Количество()

Проверить наличие всех ключей из первой структуры во второй с помощью Структура2.Свойство(Ключ)

Сравнить значения для каждого ключа в цикле

Использовать ПолноеСравнение(Структура1, Структура2) (если доступно)-->

6. Функция СравнитьЗначения() и её аналоги

Функция СравнитьЗначения(Значение1, Значение2, ..., ТолькоП Без параметра ТолькоТип сравнивает и значения, и типы.

  • 🔍 С параметром ТолькоТип = Истина проверяет только совпадение типов.
  • 🔍 Поддерживает сравнение произвольного количества значений (все должны быть равны).
  • Примеры использования:

    // Сравнение значения и типа
    

    Результат = СравнитьЗначения(10, "10"); // Ложь (разные типы)

    // Сравнение только типов

    Результат = СравнитьЗначения(10, "10", Истина); // Ложь (Число ≠ Строка)

    // Сравнение нескольких значений

    Результат = СравнитьЗначения(1, 1, 1, 1); // Истина

    Альтернативные функции:

    • 🔄 ПолноеСравнение() — рекурсивное сравнение составных типов (массивов, структур).
    • 🔄 НРег() — приведение строки к нижнему регистру для сравнения без учёта регистра.
    • 🔄 СравнитьСтроки() — сравнение строк с учётом/без учёта регистра.
    ⚠️ Внимание: Функция СравнитьЗначения() может работать медленнее оператора = для примитивных типов, так как выполняет дополнительные проверки. В критичных по производительности участках кода используйте операторы сравнения.
    💡

    Для проверки типа значения без сравнения его содержимого используйте конструкцию ТипЗнч(Значение) = Тип("Число"). Это быстрее, чем СравнитьЗначения(..., Истина).

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

    Даже опытные разработчики допускают ошибки при сравнении данных в . Рассмотрим самые распространённые случаи:

    1. 🐛 Сравнение чисел и строк: Если Код = "123" Тогда сработает, если Код — число 123, но не сработает для строки "00123". Всегда приводите типы явно: Если Строка(Код) = "123" Тогда.
    2. 🐛 Проверка на пустую ссылку: Если Документ = ПустаяСсылка Тогда — неверно. Правильно: Если Документ.Пустая() Тогда.
    3. 🐛 Сравнение дат с временем: Если Дата1 = Дата2 Тогда может не сработать из-за разницы в секундах. Используйте НачалоДня().
    4. 🐛 Сравнение коллекций по ссылке: Если Массив1 = Массив2 Тогда всегда вернёт Ложь, даже если содержимое одинаково.

    Как избежать ошибок:

    • 🛡️ Всегда явно приводите типы перед сравнением (например, Число(), Строка(), Дата()).
    • 🛡️ Для ссылок используйте методы .Пустая() или .УникальныйИдентификатор().
    • 🛡️ Для коллекций пишите собственные функции сравнения или используйте ПолноеСравнение().

    Частые вопросы (FAQ)

    Почему Число(10) = "10" возвращает Истина, а СравнитьЗначения(10, "10")Ложь?

    Оператор = выполняет неявное приведение типов: строка "10" автоматически преобразуется в число. Функция СравнитьЗначения() сравнивает и значения, и типы, поэтому возвращает Ложь.

    Как сравнить две структуры по содержимому?

    Нужно вручную пройти по всем ключам и сравнить значения:

    Процедура СтруктурыРавны(Структура1, Структура2)
    

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

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

    КонецЕсли;

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

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

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

    КонецЕсли;

    Если Структура1[Ключ] <> Структура2[Ключ] Тогда

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

    КонецЕсли;

    КонецЦикла;

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

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

    В новых версиях платформы можно использовать ПолноеСравнение(Структура1, Структура2).

    Чем отличается Неопределено от NULL?

    NULL — это значение поля в базе данных (например, незаполненный реквизит документа). Неопределено — это состояние переменной в коде, которой не присвоено значение. Они не взаимозаменяемы:

    ЗначениеИзБазы = Документ.Реквизит; // Может быть NULL
    

    Переменная; // Неопределено, если не инициализирована

    Как сравнить два объекта по реквизитам, а не по ссылке?

    Нужно явно сравнивать каждый реквизит:

    Если Объект1.Номер = Объект2.Номер И
    

    Объект1.Дата = Объект2.Дата И

    Объект1.Сумма = Объект2.Сумма Тогда

    // Объекты совпадают по реквизитам

    КонецЕсли;

    Для сложных объектов можно написать универсальную функцию сравнения или использовать ПолноеСравнение().

    Почему после обновления платформы сравнение коллекций стало работать иначе?

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