Сравнение данных в 1С:Предприятие — одна из самых частых операций, с которой сталкиваются разработчики. На первый взгляд кажется, что всё просто: достаточно поставить оператор = или <>, и платформа сама разберётся. Но на практике даже опытные программисты сталкиваются с неожиданными результатами при сравнении ссылок на объекты, значений NULL, коллекций или примитивных типов разных форм. Например, почему Число(10) = 10 возвращает Истина, а Строка("10") = 10 — Ложь? Или как правильно проверить, что две ссылки указывают на один и тот же документ, а не просто имеют одинаковые реквизиты?
В этой статье мы разберём все нюансы сравнения типов данных в 1С, включая скрытые особенности операторов, функции СравнитьЗначения() и ТипЗнч(), а также типичные ошибки, которые приводят к багам в коде. Вы узнаете, как платформа преобразует типы при сравнении, почему иногда лучше использовать ПолноеСравнение(), и как избежать ловушек с Неопределено и NULL. Материал будет полезен как начинающим разработчикам, так и опытным специалистам, которые хотят систематизировать знания.
1. Базовые операторы сравнения: ==, <>, >, <
В 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 и Неопределено: ловушки и решения
В 1С есть два "пустых" значения: 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. Функция СравнитьЗначения() и её аналоги
Функция Примеры использования: Результат = СравнитьЗначения(10, "10"); // Ложь (разные типы) // Сравнение только типов Результат = СравнитьЗначения(10, "10", Истина); // Ложь (Число ≠ Строка) // Сравнение нескольких значений Результат = СравнитьЗначения(1, 1, 1, 1); // ИстинаСравнитьЗначения(Значение1, Значение2, ..., ТолькоП Без параметра ТолькоТип сравнивает и значения, и типы.
ТолькоТип = Истина проверяет только совпадение типов.// Сравнение значения и типа
Альтернативные функции:
- 🔄
ПолноеСравнение()— рекурсивное сравнение составных типов (массивов, структур). - 🔄
НРег()— приведение строки к нижнему регистру для сравнения без учёта регистра. - 🔄
СравнитьСтроки()— сравнение строк с учётом/без учёта регистра.
⚠️ Внимание: ФункцияСравнитьЗначения()может работать медленнее оператора=для примитивных типов, так как выполняет дополнительные проверки. В критичных по производительности участках кода используйте операторы сравнения.
Для проверки типа значения без сравнения его содержимого используйте конструкцию ТипЗнч(Значение) = Тип("Число"). Это быстрее, чем СравнитьЗначения(..., Истина).
7. Типичные ошибки и как их избежать
Даже опытные разработчики допускают ошибки при сравнении данных в 1С. Рассмотрим самые распространённые случаи:
- 🐛 Сравнение чисел и строк:
Если Код = "123" Тогдасработает, еслиКод— число123, но не сработает для строки"00123". Всегда приводите типы явно:Если Строка(Код) = "123" Тогда. - 🐛 Проверка на пустую ссылку:
Если Документ = ПустаяСсылка Тогда— неверно. Правильно:Если Документ.Пустая() Тогда. - 🐛 Сравнение дат с временем:
Если Дата1 = Дата2 Тогдаможет не сработать из-за разницы в секундах. ИспользуйтеНачалоДня(). - 🐛 Сравнение коллекций по ссылке:
Если Массив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+) были внесены изменения в механизм сравнения составных типов. Например, функция ПолноеСравнение() стала рекурсивно сравнивать вложенные коллекции. Проверьте версию платформы и документацию к ней.