При обходе коллекций (массивов, таблиц значений, списков значений, выборок) во встроенном языке платформы «1С:Предприятие» нередко возникает задача: при выполнении определенного логического условия прекратить дальнейшие действия с текущим элементом и сразу перейти к следующему. Разберем основные способы реализации такого поведения, правила применения операторов управления циклом и критические ошибки, которых следует избегать.
Для мгновенного завершения текущей итерации и перехода к следующему элементу коллекции используется оператор Продолжить. Как только платформа встречает эту инструкцию, выполнение последующих строк кода внутри тела цикла для текущего элемента прекращается, и цикл переходит к следующей итерации.
Рассмотрим типовой пример обхода коллекции с использованием оператора Продолжить:
Для Каждого Элемент Из Коллекция Цикл
Если Элемент.НеТребуетОбработки Тогда
Продолжить;
КонецЕсли;
// Ниже выполняется полезная логика только для подходящих элементов
ОбработатьЭлемент(Элемент);
КонецЦикла;
Важно четко различать назначение двух операторов управления ходом цикла:
КонецЦикла, а оставшиеся элементы коллекции не обрабатываются вовсе.Посмотрим на пример с условием полной остановки обхода:
Для Каждого СтрокаТаблицы Из ТаблицаТоваров Цикл
Если СтрокаТаблицы.Количество <= 0 Тогда
Продолжить; // Пропускаем позицию с нулевым остатком и берем следующую
КонецЕсли;
Если СтрокаТаблицы.КритическаяОшибка Тогда
Прервать; // Полностью останавливаем обработку таблицы
КонецЕсли;
ВыполнитьПроведение(СтрокаТаблицы);
КонецЦикла;
Если логика пропуска простая, а тело цикла содержит небольшое количество кода, можно обойтись без оператора досрочного перехода, обернув полезное действие в условие с блоком Иначе или проверкой на отрицание:
Для Каждого Элемент Из Коллекция Цикл
Если Не Элемент.НеТребуетОбработки Тогда
ОбработатьЭлемент(Элемент);
КонецЕсли;
КонецЦикла;
По стандартам разработки 1С рекомендуется минимизировать количество разрозненных выходов Продолжить и Прервать внутри одного сложного цикла, так как большое их число снижает читаемость кода. При наличии множества условий предпочтительно выносить тело итерации в отдельную процедуру или функцию.
Проанализируем важный нюанс: оператор Продолжить действует строго в пределах того цикла, в котором он вызван. Если код выполняется во внутреннем цикле, вызов Продолжить не переключит итерацию внешнего цикла.
Для Каждого Документ Из СписокДокументов Цикл
Для Каждого СтрокаТовара Из Документ.Товары Цикл
Если СтрокаТовара.Услуга Тогда
Продолжить; // Переход к следующей строке товара текущего документа
КонецЕсли;
ПроверитьЦену(СтрокаТовара);
КонецЦикла;
КонецЦикла;
Если требуется при условии во внутреннем цикле сразу перейти к следующему элементу внешнего цикла, по стандартам 1С используют логические флаги или выносят вложенный цикл в отдельную функцию, возвращающую булево значение через Возврат.
Если перебор организуется не через Для каждого, а через Пока с ручным счетчиком, вызов Продолжить до изменения переменной-счетчика приведет к мертвому зависанию сеанса 1С.
Разберем потенциально опасный пример и правильную реализацию:
// ОШИБКА: при срабатывании условия счетчик не увеличится, возникнет бесконечный цикл
Индекс = 0;
Пока Индекс < МассивДанных.Количество() Цикл
Если МассивДанных[Индекс] = Неопределено Тогда
Продолжить; // Зависание!
КонецЕсли;
Индекс = Индекс + 1;
КонецЦикла;
// ПРАВИЛЬНО: увеличиваем индекс до вызова перехода или перед условием
Индекс = 0;
Пока Индекс < МассивДанных.Количество() Цикл
Элемент = МассивДанных[Индекс];
Индекс = Индекс + 1;
Если Элемент = Неопределено Тогда
Продолжить; // Безопасный переход
КонецЕсли;
ОбработатьДанные(Элемент);
КонецЦикла;
Частая ошибка начинающих разработчиков — попытка удалить элемент из коллекции прямо внутри цикла Для каждого с помощью методов Удалить(). Это приводит к сдвигу индексов, в результате чего платформа пропускает следующий за удаленным элемент без обработки либо выдает системную ошибку.
Разберем два корректных способа удаления элементов по условию:
Для Индекс = -(Коллекция.Количество() - 1) По 0 Цикл
Элемент = Коллекция[-Индекс];
Если Элемент.ТребуетУдаления Тогда
Коллекция.Удалить(-Индекс);
КонецЕсли;
КонецЦикла;
УдаляемыеСтроки = Новый Массив;
Для Каждого Строка Из ТаблицаДанных Цикл
Если Строка.Неактуально Тогда
УдаляемыеСтроки.Добавить(Строка);
КонецЕсли;
КонецЦикла;
Для Каждого Строка Из УдаляемыеСтроки Цикл
ТаблицаДанных.Строки.Удалить(Строка);
КонецЦикла;
Если для выборки большого объема данных используется цикл с проверками условий через Продолжить, выясним, как оптимизировать быстродействие:
ГДЕ. Это исключит лишнюю передачу данных между СУБД и сервером 1С.ТаблицаЗначений.НайтиСтроки(СтруктураОтбора) или ТаблицаЗначений.Скопировать(СтруктураОтбора).ТаблицаЗначений.Колонки.Индексировать.