К статье
Практический материал

Разработка и Конфигурация · 10 мин

Какие бывают циклы в 1С и как их использовать

Разбираем виды циклов во встроенном языке 1С: Для…Цикл, Для Каждого…Из…Цикл, Пока…Цикл. Примеры кода, прерывание, типичные ошибки и выбор подходящего цикла.

Циклы во встроенном языке 1С нужны везде, где требуется повторить одни и те же действия: обойти строки табличной части документа, перебрать записи регистра, сформировать несколько печатных форм или накопить итог по коллекции. Без циклов практически невозможно написать ни один прикладной алгоритм — от простого расчёта суммы до сложной обработки данных.

В языке 1С существует три вида циклов: Для…Цикл (со счётчиком), Для Каждого…Из…Цикл (обход коллекции) и Пока…Цикл (с условием). У каждого своя область применения, свои ограничения и типичные ошибки. Неправильный выбор цикла приводит либо к лишнему коду, либо к бесконечному выполнению и зависанию сеанса.

Ниже разберём синтаксис каждого вида, покажем рабочие примеры на встроенном языке, объясним, как прерывать и пропускать итерации, и дадим критерии выбора подходящей конструкции.

Цикл Для…Цикл: повторения с известным счётчиком

Конструкция Для…Цикл применяется, когда заранее известно количество итераций или нужен числовой счётчик. Переменная-счётчик автоматически увеличивается на единицу при каждом проходе, шаг изменить нельзя. Синтаксис:

Для Счетчик = 1 По 10 Цикл

Сообщить("Итерация № " + Счетчик);

КонецЦикла;

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

Типичный прикладной сценарий — обход табличной части по индексу, когда нужен номер строки:

Для Индекс = 0 По ТабличнаяЧасть.Количество() - 1 Цикл

СтрокаТЧ = ТабличнаяЧасть[Индекс];

СтрокаТЧ.Сумма = СтрокаТЧ.Количество * СтрокаТЧ.Цена;

КонецЦикла;

Обратите внимание: индексация коллекций в 1С начинается с нуля, поэтому верхняя граница — Количество() - 1. Ошибка «на единицу» здесь — самая частая причина исключения «Индекс находится за границами массива».

Цикл Для Каждого…Из…Цикл: обход коллекций

Конструкция Для Каждого…Из…Цикл — основной рабочий инструмент в прикладном коде. Она перебирает элементы коллекции: массива, структуры, таблицы значений, табличной части, выборки результата запроса, списка значений. На каждой итерации переменная цикла получает ссылку на очередной элемент.

Для Каждого СтрокаТовара Из Объект.Товары Цикл

Если СтрокаТовара.Количество = 0 Тогда

Сообщить("В строке " + СтрокаТовара.НомерСтроки + " не указано количество");

КонецЕсли;

КонецЦикла;

Тот же подход работает с выборкой запроса — это стандартный способ обработки данных из базы:

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл

// обработка текущей записи выборки

КонецЦикла;

Здесь важный нюанс: выборка запроса обходится через метод Следующий() в цикле Пока, а не через Для Каждого. Хотя Для Каждого по выборке формально выполнится, идиоматически правильный и предсказуемый способ — именно Пока Выборка.Следующий().

Обход структуры и соответствия

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

Для Каждого Элемент Из СоответствиеКурсов Цикл

Сообщить(Элемент.Ключ + ": " + Элемент.Значение);

КонецЦикла;

Цикл Пока…Цикл: повторения по условию

Конструкция Пока…Цикл выполняется, пока условие истинно. Условие проверяется перед каждой итерацией, поэтому если оно ложно с самого начала — тело цикла не выполнится ни разу:

Пока Выборка.Следующий() Цикл

ИтоговаяСумма = ИтоговаяСумма + Выборка.Сумма;

КонецЦикла;

Этот цикл выбирают, когда число повторений заранее неизвестно: чтение файла построчно, движение по выборке запроса, итеративные расчёты до достижения точности, ожидание освобождения ресурса.

Главный риск — бесконечный цикл. Если условие никогда не станет ложным, сеанс зависнет, а на сервере процесс будет потреблять ресурсы до принудительного завершения. Всегда проверяйте, что внутри тела цикла есть действие, которое рано или поздно изменит условие.

Типичные ошибки
01
Бесконечный цикл Пока: внутри тела не изменяется ни одна переменная условия — сеанс зависает
02
Обход табличной части с 1 по Количество() вместо 0 по Количество()-1 — ошибка выхода за границы
03
Удаление строк коллекции прямо внутри цикла Для Каждого — часть строк пропускается
04
Вложенные циклы с одинаковыми именами переменных — внутренний цикл портит счётчик внешнего

Управление выполнением: Прервать и Продолжить

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

Для Каждого Строка Из ТаблицаДанных Цикл

Если Не ЗначениеЗаполнено(Строка.Номенклатура) Тогда

Продолжить; // пропускаем пустые строки

КонецЕсли;

Если Строка.ЭтоСтопПризнак Тогда

Прервать; // дальше обрабатывать не нужно

КонецЕсли;

ОбработатьСтроку(Строка);

КонецЦикла;

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

Как выбрать подходящий цикл

Выбор определяется источником данных и тем, что известно заранее. Ориентируйтесь на простые правила:

Маршрут решения

Как выбрать действие

Известно точное число повторений или нужен числовой счётчикИспользуйте Для…Цикл
Нужно обойти массив, таблицу значений, табличную часть, структуруИспользуйте Для Каждого…Из…Цикл
Обрабатываете выборку запроса или читаете файл построчноИспользуйте Пока Выборка.Следующий() Цикл или Пока с условием чтения
Число повторений зависит от результата вычислений внутри циклаИспользуйте Пока…Цикл и гарантируйте изменение условия
КритерийДля…ЦиклДля Каждого…ЦиклПока…Цикл
Число итерацийИзвестно заранееРавно размеру коллекцииНеизвестно
Типичный источникСчётчик, диапазонКоллекцияВыборка, файл, условие
Риск бесконечного циклаНетНетДа, при ошибке в условии
Доступ к индексуЕсть напрямуюЧерез отдельный счётчикЧерез отдельный счётчик

Если при обходе коллекции нужен и элемент, и его порядковый номер, заведите отдельную переменную-счётчик и увеличивайте её внутри Для Каждого — это читабельнее, чем переписывание на цикл по индексу.

Вложенные циклы и производительность

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

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

Если внутри цикла нужно многократно искать строки в таблице значений, заранее создайте по ней индекс (метод Индексы.Добавить) или преобразуйте её в соответствие — поиск по ключу соответствия работает значительно быстрее перебора НайтиСтроки на каждой итерации.
ПЗ
Практическое замечание

Проверка результата работы цикла

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

Контрольные точки

Как проверить результат

Обход пустой табличной части
Норма

Цикл не выполняется, ошибок нет

Тревожный признак

Ошибка обращения по индексу или исключение

Количество обработанных элементов
Норма

Совпадает с размером коллекции

Тревожный признак

Меньше — где-то срабатывает Прервать или пропуск при удалении

Время выполнения на реальном объёме
Норма

Линейно растёт от числа элементов

Тревожный признак

Резко растёт из-за запросов внутри цикла

Завершение цикла Пока
Норма

Условие становится ложным за конечное число шагов

Тревожный признак

Сеанс зависает — условие не изменяется

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

Итог

Что важно запомнить

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

Частые вопросы о циклах в 1С

Можно ли изменить шаг цикла Для, например на 2 или на -1?

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

Как прервать сразу два вложенных цикла?

Специального оператора для этого нет. Обычно заводят переменную-флаг: внутренний цикл устанавливает её и прерывается, а внешний проверяет флаг после внутреннего цикла и тоже выполняет Прервать. Альтернатива — вынести логику в функцию и выйти из неё оператором Возврат.

Что быстрее: Для Каждого или Для по индексу?

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

Почему при удалении строк в цикле пропускаются элементы?

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

Как обойти таблицу значений в обратном порядке?

Используйте цикл Пока со счётчиком, который уменьшается от Количество() - 1 до нуля, либо отсортируйте таблицу в обратном порядке и обойдите её обычным циклом Для Каждого. Цикл Для с отрицательным шагом в 1С отсутствует.

Можно ли использовать цикл внутри запроса?

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