При анализе кода типовых конфигураций 1С, например, 1С:ERP, можно столкнуться с конструкциями, которые вызывают вопросы у разработчиков. Один из таких моментов — проверка результата поиска элемента в массиве. Вместо привычного прямого сравнения со значением Неопределено, используется сравнение типа результата. Давайте детально разберем, почему так делают, какие у этого подхода есть плюсы и минусы, и как все-таки писать код правильнее и читабельнее.
Проанализируем две конструкции. Первая, найденная в типовой конфигурации:
// Способ 1: Сравнение по типу
Если ТипЗнч(МассивСтатусов.Найти(Статус)) = Тип("Неопределено") Тогда
// Элемент не найден
КонецЕсли;
И вторая, более распространенная и интуитивно понятная:
// Способ 2: Сравнение по значению
Если МассивСтатусов.Найти(Статус) = Неопределено Тогда
// Элемент не найден
КонецЕсли;
Основной вопрос: чем первый способ лучше или правильнее второго и есть ли в его использовании скрытый смысл?
Сразу отметим, что стандартным, наиболее читаемым и рекомендуемым способом является прямое сравнение со значением Неопределено. Этот подход понятен любому разработчику 1С, он лаконичен и полностью соответствует своему назначению. Метод Массив.Найти() возвращает либо индекс найденного элемента (тип Число), либо значение Неопределено, если элемент не найден. Прямое сравнение — самый логичный способ проверить этот результат.
Большинство разработчиков и учебных материалов по 1С используют именно конструкцию Результат = Неопределено. Поэтому, если у вас нет веских причин делать иначе, всегда выбирайте этот вариант для лучшей читаемости и поддержки кода.
Основное предположение, почему в типовых конфигурациях может использоваться сравнение типов, связано с производительностью. Рассмотрим эту теорию подробнее.
Платформа 1С для хранения переменных использует внутренний механизм, похожий на тип variant. Каждая переменная, по сути, хранит не только свое значение, но и информацию о своем типе. Упрощенно, в памяти это можно представить как структуру, где вначале идет идентификатор типа, а затем — само значение.
Исходя из этого, родилась гипотеза: операция получения типа ТипЗнч() может быть очень быстрой, так как для этого достаточно прочитать только первую часть структуры в памяти (идентификатор типа). А для сравнения самих значений платформе может потребоваться прочитать всю область памяти, выделенную под значение. Если значение "тяжелое" (например, большая строка или структура), то сравнение значений будет медленнее.
Таким образом, логика сторонников этого подхода такова:
Неопределено, у него всего одно возможное значение. Поэтому, если мы убедились, что тип переменной — Неопределено, мы можем быть уверены и в ее значении.На первый взгляд, это звучит логично, особенно если речь идет о высоконагруженных системах и операциях, выполняемых в циклах миллионы раз. Однако давайте посмотрим на аргументы против.
Несмотря на кажущуюся логичность, у теории о приросте производительности есть серьезные слабые места, особенно в контексте рассматриваемого примера.
1. Контекст операции. В нашем случае мы анализируем результат функции Массив.Найти(). Эта функция может вернуть только два варианта:
Число (индекс элемента)НеопределеноНи один из этих типов не является "тяжелым". Это простые, примитивные типы, сравнение которых происходит очень быстро. Здесь нет "огромных объемов данных", о которых шла речь в гипотезе. Платформа 1С оптимизирована для работы с такими базовыми типами.
2. Сравнение с Неопределено уже оптимизировано. Внутренние механизмы платформы при выполнении операции Результат = Неопределено, скорее всего, и так в первую очередь проверяют тип операндов. Обнаружив, что один из них имеет тип Неопределено, платформа может мгновенно дать результат, не прибегая к сложному сравнению содержимого. Фактически, прямое сравнение уже выполняет ту самую "оптимизацию" под капотом.
3. Ничтожный выигрыш. Даже если предположить, что сравнение типов на несколько тактов процессора быстрее, этот выигрыш абсолютно ничтожен на фоне времени выполнения самой функции Массив.Найти(). Поиск в массиве, особенно в большом, — несравнимо более ресурсоемкая операция. Оптимизировать сравнение результата — это как экономить миллиграммы, перевозя тонны груза. В большинстве случаев, как и в примере из темы, такая проверка выполняется однократно (например, при открытии формы) и на небольшом массиве. Экономия времени будет измеряться наносекундами, что не имеет никакого практического смысла.
Если производительность — не главная причина, то почему такой код все же появляется в продуктах от фирмы "1С"? Есть несколько правдоподобных объяснений.
Если ТипЗнч(Объект) = Тип("СправочникСсылка.Номенклатура") Тогда
// ...
КонецЕсли;
ТипЗнч(...) = Тип("Неопределено").
Помимо двух рассмотренных вариантов, существуют и другие способы проверить, был ли найден элемент в массиве. Рассмотрим их для полноты картины.
1. Проверка на тип "Число"
Поскольку в случае успеха Найти() возвращает число (индекс), можно проверять именно этот тип.
Если ТипЗнч(МассивСтатусов.Найти(Статус)) = Тип("Число") Тогда
// Элемент найден
КонецЕсли;
Этот способ логически корректен, но менее популярен, чем сравнение с Неопределено, и также страдает от избыточности, как и проверка типа "Неопределено".
2. Сравнение с нулем
Индексация массивов в 1С начинается с 0. Это значит, что если элемент найден, его индекс всегда будет больше или равен нулю.
Если МассивСтатусов.Найти(Статус) >= 0 Тогда
// Элемент найден
КонецЕсли;
Этот подход тоже абсолютно корректен и довольно популярен в других языках программирования. В 1С он встречается реже, возможно, из-за того, что сравнение с Неопределено считается более "идиоматичным" для платформы, то есть более соответствующим ее стилю и традициям.
Подводя итог, можно с уверенностью сказать, что конструкция Если Массив.Найти(Значение) = Неопределено Тогда является предпочтительным методом проверки. Он:
Использование сравнения через ТипЗнч(...) = Тип("Неопределено") не дает практически значимых преимуществ в производительности, усложняет код и, скорее всего, является следствием либо ошибки копирования, либо следования избыточным стандартам кодирования. Не стоит рассматривать этот пример из типовой конфигурации как образец для подражания в повседневной разработке.