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