Разработка и Конфигурация · 12 мин
Как прервать цикл «Для Каждого» в 1С
Как прервать цикл «Для Каждого» в 1С: оператор Прервать, условия выхода, отличия от Продолжить и Возврат, типичные ошибки и примеры кода на встроенном языке.
Цикл «Для Каждого … Цикл» — один из самых часто используемых операторов встроенного языка 1С: с его помощью перебирают строки табличных частей, массивы, строки таблиц значений и выборки. На практике полный перебор нужен далеко не всегда: если искомый элемент найден, продолжать обход бессмысленно и расточительно. Для досрочного выхода из цикла в 1С предусмотрен оператор Прервать.
Оператор Прервать немедленно завершает выполнение ближайшего цикла, внутри которого он вызван, и передаёт управление первой строке кода после ключевого слова КонецЦикла. При этом текущая итерация не довыполняется — все операторы, стоящие после Прервать внутри тела цикла, пропускаются. Это принципиальное отличие от оператора Продолжить, который лишь завершает текущую итерацию и переходит к следующему элементу.
Корректное использование Прервать важно не только для логики алгоритма, но и для производительности: на больших таблицах значений или выборках из запроса досрочный выход может сократить время выполнения процедуры в разы. Ниже разобраны синтаксис, типовые сценарии, отличия от смежных операторов и ошибки, которые чаще всего допускают разработчики.
Синтаксис оператора Прервать и минимальный пример
Конструкция «Для Каждого» перебирает элементы коллекции, присваивая очередной элемент указанной переменной на каждой итерации. Оператор Прервать размещается внутри тела цикла, практически всегда — внутри условного оператора Если, потому что безусловный выход на первой же итерации делает цикл бессмысленным.
Типовой пример поиска строки в табличной части документа:
НайденнаяСтрока = Неопределено;
Для Каждого СтрокаТовары Из Объект.Товары Цикл
Если СтрокаТовары.Номенклатура = ИскомаяНоменклатура Тогда
НайденнаяСтрока = СтрокаТовары;
Прервать;
КонецЕсли;
КонецЦикла;
Если НайденнаяСтрока <> Неопределено Тогда
Сообщить("Строка найдена: " + НайденнаяСтрока.НомерСтроки);
КонецЕсли;
Здесь цикл обходит табличную часть, пока не встретит нужную номенклатуру. Как только соответствие найдено, ссылка на строку сохраняется в переменную, и Прервать завершает обход. Если подходящей строки нет, цикл отработает до конца естественным образом, а переменная останется равной Неопределено — это и есть признак того, что выход произошёл не по Прервать, а по завершении коллекции.
Обратите внимание: Прервать не требует параметров и не возвращает значений. Это управляющий оператор, а не функция, поэтому запись вида Результат = Прервать(); является синтаксической ошибкой.
Чем Прервать отличается от Продолжить и Возврат
Новички часто путают три управляющих оператора, которые внешне похожи, но ведут себя принципиально по-разному. Неправильный выбор между ними — одна из самых распространённых причин логических ошибок в обработках.
| Оператор | Что делает | Куда передаёт управление |
|---|---|---|
Прервать | Полностью завершает цикл | На первую строку после КонецЦикла |
Продолжить | Завершает только текущую итерацию | На начало цикла, следующий элемент коллекции |
Возврат | Завершает всю процедуру или функцию | В точку вызова процедуры/функции |
Ключевое правило выбора: если нужно найти один элемент и остановиться — используйте Прервать. Если нужно обработать все элементы, но часть из них пропустить по условию — используйте Продолжить. Если найденный результат делает бессмысленным дальнейшее выполнение всей процедуры — уместен Возврат.
Пример с Продолжить для сравнения:
Для Каждого СтрокаТовары Из Объект.Товары Цикл
Если СтрокаТовары.Количество = 0 Тогда
Продолжить; // нулевые строки пропускаем, но цикл идёт дальше
КонецЕсли;
СуммаИтог = СуммаИтог + СтрокаТовары.Сумма;
КонецЦикла;
Если в этом примере заменить Продолжить на Прервать, первая же строка с нулевым количеством остановит весь обход, и сумма будет посчитана неверно. Такие ошибки трудно отловить, потому что код синтаксически корректен и падает только на определённых данных.
Сравнение вариантов выхода
Когда найден единственный нужный элемент и дальнейший перебор не нужен. Не подходит, если надо обработать несколько совпадений.
Когда часть элементов нужно пропустить, но обойти коллекцию до конца. Не завершает цикл.
Когда результат найден и вся оставшаяся логика процедуры не нужна. Завершает всю процедуру, а не только цикл.
Типовые сценарии применения
Поиск первого подходящего элемента
Самый частый сценарий — проверка существования или поиск единственного элемента: есть ли в заказе товар из запрещённого списка, найден ли контрагент с заданным ИНН, присутствует ли строка с ошибкой. Как только ответ «да» получен, дальнейший перебор не нужен, и Прервать экономит ресурсы.
Выход по достижении лимита
Второй сценарий — ограничение количества обработанных элементов. Например, нужно подобрать не более пяти свободных партий для резервирования. Счётчик увеличивается на каждой подходящей строке, и при достижении лимита цикл прерывается:
Подобрано = 0;
Для Каждого СтрокаПартии Из ТаблицаПартий Цикл
Если СтрокаПартии.СвободныйОстаток > 0 Тогда
// логика резервирования
Подобрано = Подобрано + 1;
КонецЕсли;
Если Подобрано >= 5 Тогда
Прервать;
КонецЕсли;
КонецЦикла;
Аварийный выход при ошибке данных
Третий сценарий — обнаружение неконсистентных данных, при которых продолжать обход бессмысленно или опасно. Например, если в строке обнаружена незаполненная обязательная аналитика, цикл прерывают, фиксируют ошибку и отказываются от проведения документа. Здесь важно, чтобы после КонецЦикла стояла проверка признака ошибки, иначе документ может быть обработан как корректный.
- 1Определите условие, при котором дальнейший перебор не нужен
- 2Перед циклом объявите переменную-результат и инициализируйте её (например, Неопределено)
- 3Внутри цикла добавьте Если <условие> Тогда ... Прервать; КонецЕсли
- 4Перед Прервать сохраните найденное значение в переменную-результат
- 5После КонецЦикла проверьте переменную-результат, чтобы отличить выход по Прервать от полного перебора
- 6Протестируйте на данных, где элемент есть, и на данных, где его нет
Поведение Прервать во вложенных циклах
Оператор Прервать действует только на тот цикл, в теле которого он непосредственно находится. Если циклы вложены друг в друга, прерывается лишь внутренний, а внешний продолжает перебор со следующего элемента. Это часто становится источником ошибок: разработчик ожидает полного выхода из обоих циклов, а получает продолжение внешнего обхода.
Для выхода сразу из двух и более уровней вложенности применяют флаг-переменную:
НужноПрерватьВсё = Ложь;
Для Каждого Заказ Из СписокЗаказов Цикл
Для Каждого СтрокаЗаказа Из Заказ.Товары Цикл
Если СтрокаЗаказа.Номенклатура = ИскомаяНоменклатура Тогда
НужноПрерватьВсё = Истина;
Прервать; // выходим из внутреннего цикла
КонецЕсли;
КонецЦикла;
Если НужноПрерватьВсё Тогда
Прервать; // выходим из внешнего цикла
КонецЕсли;
КонецЦикла;
Альтернатива флагу — вынести поиск в отдельную функцию и использовать Возврат: он выходит из всех циклов сразу, поскольку завершает функцию целиком. Такой подход обычно читается лучше, особенно при трёх и более уровнях вложенности, где цепочка флагов становится громоздкой.
Производительность и когда Прервать не нужен
На коллекциях из десятков строк разница между полным перебором и досрочным выходом незаметна. Но на выборках из запросов по крупным таблицам или таблицах значений с десятками тысяч строк экономия становится ощутимой, особенно если внутри итерации выполняются обращения к реквизитам через точку, вызывающие дополнительные запросы к базе.
При этом важно понимать: если задача сводится к поиску по ключевому полю, часто цикл с Прервать вообще не нужен. У таблиц значений есть метод Найти(), у табличных частей — Найти() и НайтиСтроки(), а для поиска по данным информационной базы правильнее использовать запрос с отбором, а не перебор. Досрочный выход из цикла оправдан там, где условие поиска сложное и не выражается простым равенством: например, поиск по части строки, по вычисляемому условию или по результату функциональной проверки.
Ещё одна ситуация, где Прервать не поможет, — обход результата запроса, когда нужно не найти, а посчитать или сгруппировать данные. Такие задачи решаются на уровне текста запроса (агрегатные функции, группировки), и попытка эмулировать их циклом с условиями почти всегда медленнее и сложнее в сопровождении.
Как выбрать подход
Типичные ошибки и как их проверить
Первая ошибка — отсутствие проверки результата после цикла. Разработчик прерывает цикл при нахождении элемента, но не различает ситуации «нашёл и прервал» и «не нашёл и дошёл до конца». Всегда сохраняйте результат в переменную до Прервать и анализируйте её после КонецЦикла.
Вторая ошибка — прерывание не того цикла во вложенных конструкциях, описанная выше. Третья — модификация коллекции во время перебора: удаление или добавление строк табличной части внутри «Для Каждого» может привести к пропуску элементов или ошибке обхода. Если нужно удалять строки, собирайте их в отдельный массив внутри цикла и удаляйте после его завершения.
Четвёртая ошибка — использование Прервать вместо Продолжить при фильтрации: цикл останавливается на первом неподходящем элементе, и итоговые суммы или счётчики оказываются заниженными. Такой дефект проявляется только на определённых наборах данных, поэтому тестировать обработку нужно и на данных, где условие срабатывает, и на данных, где оно не срабатывает ни разу.
Как проверить результат
Цикл завершается досрочно, результат сохранён в переменной
Перебор идёт до конца или переменная-результат пуста
Цикл отрабатывает полностью, переменная-результат остаётся в исходном значении
Код после цикла работает так, будто элемент найден
Внешний цикл тоже останавливается по флагу или выходу через Возврат
Внешний цикл продолжает обход после срабатывания Прервать во внутреннем
Частые вопросы
Можно ли использовать Прервать вне цикла?
Нет. Оператор допустим только внутри тела циклов «Для Каждого», «Для … По … Цикл» и «Пока». Размещение его вне цикла вызовет синтаксическую ошибку при проверке модуля.
Прервать завершает функцию целиком?
Нет, он завершает только цикл. Для досрочного завершения процедуры или функции используется оператор Возврат. Если из глубоко вложенного цикла нужно сразу выйти из функции — Возврат обычно удобнее цепочки Прервать с флагами.
Чем заменить Прервать при поиске по таблице значений?
Для поиска по равенству одного или нескольких полей используйте метод Найти(Значение, Колонки) или НайтиСтроки(Отбор). Они короче, читаются лучше и не требуют ручного цикла. Цикл с Прервать оставьте для сложных вычисляемых условий.
Работает ли Прервать в цикле по выборке запроса?
Да, выборка запроса обходится циклом «Пока Выборка.Следующий() Цикл», и Прервать в нём работает так же. Учтите, что если выборка большая, а нужен лишь факт наличия записи, эффективнее сформулировать запрос так, чтобы он сразу вернул ограниченный результат.
Откатывает ли Прервать изменения, сделанные в цикле?
Нет. Все изменения, внесённые на предыдущих итерациях, сохраняются. Если цикл записывает объекты в базу и при прерывании нужно отменить всё сделанное, обрамляйте обработку транзакцией и вызывайте ОтменитьТранзакцию.
Как выйти сразу из трёх вложенных циклов?
Два рабочих способа: флаг-переменная, проверяемая после каждого КонецЦикла с вызовом Прервать на каждом уровне, либо вынос логики в отдельную функцию с выходом через Возврат. При трёх уровнях вложенности вариант с функцией обычно понятнее и проще в сопровождении.
Что важно запомнить
Оператор Прервать досрочно завершает ближайший цикл и передаёт управление на строку после КонецЦикла. Перед выходом сохраняйте результат в переменную и проверяйте её после цикла. Для пропуска итерации используйте Продолжить, для выхода из процедуры — Возврат, для простого поиска по равенству — метод Найти() вместо цикла.