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