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

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

Как написать цикл в 1С: полное руководство с примерами

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

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

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

Какие виды циклов есть в 1С и когда какой выбрать

Встроенный язык 1С поддерживает три конструкции цикла. Первая — Для Счетчик = 1 По 10 Цикл … КонецЦикла; — выполняет тело цикла заданное число раз, автоматически увеличивая переменную-счётчик на единицу. Вторая — Для Каждого Строка Из Коллекция Цикл … КонецЦикла; — перебирает элементы коллекции: массива, таблицы значений, табличной части, структуры. Третья — Пока Условие Цикл … КонецЦикла; — повторяется, пока условие истинно.

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

Сравнение видов циклов

Для…Цикл

Известно число повторений или нужен индекс элемента. Ограничение: шаг счётчика всегда 1, изменить его нельзя.

Для Каждого…Цикл

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

Пока…Цикл

Число итераций заранее неизвестно: выборки запросов, чтение файлов. Ограничение: при ошибке в условии легко получить бесконечный цикл.

Цикл «Для» со счётчиком

Конструкция выглядит так: Для Счетчик = НачальноеЗначение По КонечноеЗначение Цикл, далее тело и КонецЦикла;. Счётчик объявлять заранее не нужно — переменная создаётся автоматически. Границы могут быть числами, переменными или выражениями.

// Вывод чисел от 1 до 5

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

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

КонецЦикла;

// Обратный перебор массива по индексам

Для Индекс = 0 По Массив.ВГраница() Цикл

Сообщить(Массив[Индекс]);

КонецЦикла;

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

Шаг счётчика в цикле Для всегда равен единице и изменить его нельзя. Если нужен шаг 2 или 10, увеличивайте отдельную переменную внутри тела цикла или используйте Пока.

Цикл «Для Каждого» — перебор коллекций

Это самый частый цикл в прикладном коде 1С. Он перебирает элементы любой коллекции: массива, таблицы значений, табличной части документа, строк дерева значений. Переменная цикла на каждой итерации содержит ссылку на текущий элемент.

// Перебор табличной части документа

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

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

КонецЦикла;

// Перебор таблицы значений

Для Каждого СтрокаТЗ Из ТаблицаЗначений Цикл

Сообщить(СтрокаТЗ.Номенклатура);

КонецЦикла;

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

Типичные ошибки
01
Удаление строк табличной части прямо внутри цикла «Для Каждого» — часть строк пропускается. Решение: собрать строки в массив и удалить после цикла.
02
Использование Массив.Количество() как последнего индекса в цикле «Для» — ошибка выхода за границы. Правильно: Массив.ВГраница().
03
Изменение переменной-счётчика внутри цикла «Для» — логика становится непредсказуемой, так как платформа сама увеличивает счётчик.

Цикл «Пока» и обход выборки запроса

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

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ Номенклатура.Ссылка КАК Товар ИЗ Справочник.Номенклатура КАК Номенклатура";

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

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

Сообщить(Выборка.Товар);

КонецЦикла;

При использовании Пока с собственным условием убедитесь, что внутри тела цикла что-то меняет это условие — иначе получите бесконечный цикл. Например, при ручном переборе индексов обязательно увеличивайте счётчик: Индекс = Индекс + 1;.

Операторы «Прервать» и «Продолжить»

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

Оператор Продолжить пропускает остаток тела цикла и переходит к следующей итерации. Он удобен для фильтрации: если строка не подходит по условию, её просто пропускают, не оборачивая весь остальной код в громоздкий Если…КонецЕсли.

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

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

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

КонецЕсли;

Если Строка.Номенклатура = ИскомыйТовар Тогда

Сообщить("Найдено: " + Строка.Номенклатура);

Прервать; // дальше искать не нужно

КонецЕсли;

КонецЦикла;

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

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

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

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

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

Время выполнения обработки
Норма

Растёт пропорционально объёму данных

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

При удвоении строк время выросло в десятки раз — вероятно, запрос внутри цикла

Результат перебора
Норма

Обработано ровно столько строк, сколько в коллекции

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

Часть строк пропущена — вероятно, удаление элементов внутри цикла

Поведение сеанса
Норма

Обработка завершается, клиент отвечает

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

Сеанс завис — признак бесконечного цикла

Пошагово: пишем первый цикл в конфигураторе

Порядок действий
  1. 1
    Откройте конфигуратор и создайте внешнюю обработку (Файл → Новый → Внешняя обработка) или откройте модуль существующего объекта.
  2. 2
    Добавьте в модуль формы обработки процедуру, например команду «ВыполнитьЦикл».
  3. 3
    Напишите цикл, например: Для Счетчик = 1 По 5 Цикл Сообщить(Счетчик); КонецЦикла;
  4. 4
    Сохраните обработку и откройте её в режиме 1С:Предприятие через Файл → Открыть.
  5. 5
    Нажмите кнопку команды и проверьте, что в панели сообщений появились пять строк.

Для отладки цикла поставьте точку останова внутри тела (клавиша F9 в конфигураторе) и запустите отладку (F5). В окне «Выражения» можно наблюдать, как меняются счётчик и текущий элемент на каждой итерации — это самый быстрый способ понять, почему цикл ведёт себя не так, как ожидалось.

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

Итог

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

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

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

Можно ли в цикле «Для» задать шаг, отличный от единицы?

Нет, шаг счётчика в конструкции «Для…По…Цикл» всегда равен единице. Если нужен другой шаг, используйте цикл «Пока» и увеличивайте переменную вручную, например: Индекс = Индекс + 10.

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

Оператор «Прервать» завершает только текущий цикл. Для выхода из внешнего цикла установите флаг-переменную перед «Прервать» и проверьте её во внешнем цикле, либо вынесите перебор в функцию и используйте «Возврат» — он завершит всю функцию целиком.

Чем перебор выборки запроса отличается от перебора таблицы значений?

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

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

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

Как прервать выполнение зависшего бесконечного цикла?

В клиент-серверном режиме сеанс можно завершить через консоль кластера серверов 1С. В файловом режиме поможет только закрытие процесса через диспетчер задач. Чтобы не допускать таких ситуаций, тестируйте новые циклы на копии базы и добавляйте защитный счётчик итераций с принудительным «Прервать».

Работает ли цикл «Для Каждого» со структурой и соответствием?

Да. При переборе структуры или соответствия переменная цикла содержит объект «КлючИЗначение», у которого есть свойства «Ключ» и «Значение». Например: Для Каждого Элемент Из Соответствие Цикл Сообщить(Элемент.Ключ); КонецЦикла.