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