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