Как в цикле 1С досрочно закончить обработку текущего элемента при выполнении условия?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Базовое решение: оператор Продолжить

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

Рассмотрим типовой пример обхода коллекции с использованием оператора Продолжить:


Для Каждого Элемент Из Коллекция Цикл
    Если Элемент.НеТребуетОбработки Тогда
        Продолжить;
    КонецЕсли;

    // Ниже выполняется полезная логика только для подходящих элементов
    ОбработатьЭлемент(Элемент);
КонецЦикла;

Разница между операторами Продолжить и Прервать

Важно четко различать назначение двух операторов управления ходом цикла:

  1. Оператор Продолжить: завершает только текущий шаг (итерацию) и сразу начинает обработку следующего элемента коллекции.
  2. Оператор Прервать: полностью прекращает работу всего цикла. Управление передается строке кода, следующей сразу за оператором КонецЦикла, а оставшиеся элементы коллекции не обрабатываются вовсе.

Посмотрим на пример с условием полной остановки обхода:


Для Каждого СтрокаТаблицы Из ТаблицаТоваров Цикл
    Если СтрокаТаблицы.Количество <= 0 Тогда
        Продолжить; // Пропускаем позицию с нулевым остатком и берем следующую
    КонецЕсли;

    Если СтрокаТаблицы.КритическаяОшибка Тогда
        Прервать; // Полностью останавливаем обработку таблицы
    КонецЕсли;

    ВыполнитьПроведение(СтрокаТаблицы);
КонецЦикла;

Альтернативная структура: блок Если ... Иначе

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


Для Каждого Элемент Из Коллекция Цикл
    Если Не Элемент.НеТребуетОбработки Тогда
        ОбработатьЭлемент(Элемент);
    КонецЕсли;
КонецЦикла;

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

Особенности работы оператора во вложенных циклах

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


Для Каждого Документ Из СписокДокументов Цикл
    Для Каждого СтрокаТовара Из Документ.Товары Цикл
        Если СтрокаТовара.Услуга Тогда
            Продолжить; // Переход к следующей строке товара текущего документа
        КонецЕсли;

        ПроверитьЦену(СтрокаТовара);
    КонецЦикла;
КонецЦикла;

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

Риск бесконечного зацикливания в цикле Пока

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

Разберем потенциально опасный пример и правильную реализацию:


// ОШИБКА: при срабатывании условия счетчик не увеличится, возникнет бесконечный цикл
Индекс = 0;
Пока Индекс < МассивДанных.Количество() Цикл
    Если МассивДанных[Индекс] = Неопределено Тогда
        Продолжить; // Зависание!
    КонецЕсли;
    
    Индекс = Индекс + 1;
КонецЦикла;

// ПРАВИЛЬНО: увеличиваем индекс до вызова перехода или перед условием
Индекс = 0;
Пока Индекс < МассивДанных.Количество() Цикл
    Элемент = МассивДанных[Индекс];
    Индекс = Индекс + 1;
    
    Если Элемент = Неопределено Тогда
        Продолжить; // Безопасный переход
    КонецЕсли;
    
    ОбработатьДанные(Элемент);
КонецЦикла;

Критическая ошибка: удаление элементов из коллекции в цикле Для каждого

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

Разберем два корректных способа удаления элементов по условию:

  1. Обратный обход по индексу:
    
    Для Индекс = -(Коллекция.Количество() - 1) По 0 Цикл
        Элемент = Коллекция[-Индекс];
        Если Элемент.ТребуетУдаления Тогда
            Коллекция.Удалить(-Индекс);
        КонецЕсли;
    КонецЦикла;
    
  2. Сбор удаляемых элементов во вспомогательный массив:
    
    УдаляемыеСтроки = Новый Массив;
    Для Каждого Строка Из ТаблицаДанных Цикл
        Если Строка.Неактуально Тогда
            УдаляемыеСтроки.Добавить(Строка);
        КонецЕсли;
    КонецЦикла;
    
    Для Каждого Строка Из УдаляемыеСтроки Цикл
        ТаблицаДанных.Строки.Удалить(Строка);
    КонецЦикла;
    

Оптимизация производительности: фильтрация до входа в цикл

Если для выборки большого объема данных используется цикл с проверками условий через Продолжить, выясним, как оптимизировать быстродействие:

  1. Фильтрация в запросе: если источником данных является запрос к базе, перенесите все условия отбора в секцию ГДЕ. Это исключит лишнюю передачу данных между СУБД и сервером 1С.
  2. Методы поиска таблицы значений: вместо полного перебора таблицы с пропуском строк эффективнее использовать метод ТаблицаЗначений.НайтиСтроки(СтруктураОтбора) или ТаблицаЗначений.Скопировать(СтруктураОтбора).
  3. Индексация: для ускорения поиска по колонкам таблиц значений предварительно настраивайте свойство ТаблицаЗначений.Колонки.Индексировать.
← На главную