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

Если вы только начинаете осваивать встроенный язык 1С 8.3 или переходите с других языков программирования, то вопрос "чем отличается процедура от функции?" становится критически важным. Непонимание этой разницы часто приводит к ошибкам в коде, сложностям при отладке и неоптимальной архитектуре решений. В этой статье мы не просто дадим определения, а покажем на реальных примерах, как и когда использовать каждый из этих элементов, а также раскроем малоизвестные нюансы их работы в разных версиях платформы.

Что такое процедура в 1С и зачем она нужна

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

Основное преимущество процедур заключается в их самодостаточности: они могут изменять состояние системы (записывать данные в базу, модифицировать объекты), но не обязаны что-либо возвращать вызывающему коду. Это делает их идеальным инструментом для операций, где важно само действие, а не его результат.

  • 📌 Пример использования: процедура ОчиститьКэшСессии(), которая удаляет временные файлы после завершения работы пользователя.
  • 🔄 Вызов: процедуры вызываются по имени с указанием параметров (если они есть) через оператор . или Выполнить().
  • Производительность: процедуры могут быть быстрее функций в циклах, так как не тратят ресурсы на возврат значения.

Важно понимать, что процедуры могут быть глобальными (доступными из любого места конфигурации) и локальными (видимыми только в пределах модуля). Это влияет на архитектуру решения: злоупотребление глобальными процедурами ведет к "спагетти-коду", где связи между модулями становятся непрозрачными.

📊 Как часто вы используете процедуры в 1С?
Постоянно, это основа моего кода
Только для повторяющихся действий
Редеко, предпочитаю функции
Не использую, пишу код линейно

Функции в 1С: возвращаем результат

Функция, в отличие от процедуры, обязательно возвращает значение с помощью оператора Возврат. Это ключевое отличие делает функции незаменимыми в вычислениях, проверках условий и передаче данных между частями программы. Например, функция РассчитатьСкидку(Сумма, Клиент) может вернуть процент скидки, который затем будет использован в документе продажи.

Синтаксически функции объявляются с указанием типа возвращаемого значения (хотя это не обязательно в последних версиях платформы), что улучшает читаемость кода и помогает системе контролировать типы данных. В 1С:Предприятие 8.3.20+ появилась возможность указывать Возврат Неопределено, что полезно для обработки ошибок без генерации исключений.

  • 🔢 Типизация: можно явно указать тип возвращаемого значения (например, Функция ПолучитьКурсВалюты() Экспорт Число).
  • 🔄 Вызов: функции вызываются в выражениях, где требуется значение (например, Если ПолучитьСтатусЗаказа(Номер) = "Оплачен" Тогда...).
  • 🛡️ Безопасность: функции с явной типизацией помогают избежать ошибок несоответствия типов.

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

Перем Результат;

РассчитатьИтог(Документ, Результат);

Если Результат > 1000 Тогда...

можно просто:

Если РассчитатьИтог(Документ) > 1000 Тогда...

Это делает код лаконичнее и уменьшает количество промежуточных переменных.

💡

Если функция должна возвращать несколько значений, используйте структуру вместо отдельных параметров по ссылке. Например: Функция ПолучитьДанныеКлиента() Экспорт может вернуть структуру с полями Имя, Баланс, Статус.

Ключевые различия: процедуры vs функции

Чтобы окончательно разобраться в различиях, давайте systematize их в виде таблицы. Это поможет быстро сориентироваться, какой инструмент использовать в конкретной ситуации.

Критерий Процедура Функция
Возврат значения ❌ Нет ✅ Да (обязательно)
Использование в выражениях ❌ Только как оператор ✅ Можно вставить в условие или присваивание
Типизация возврата ❌ Не применимо ✅ Поддерживается (опционально)
Производительность в циклах ⚡ Быстрее (нет накладных расходов на возврат) 🐢 Медленнее (требуется упаковка результата)
Типичное применение Изменение состояния (запись в БД, модификация объектов) Вычисления, проверки, получение данных

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

Когда процедура может вернуть значение?

В редких случаях процедуры могут "возвращать" данные через параметры по ссылке (с модификатором Перем). Например:

Процедура ПолучитьДанные(Знач Результат) Экспорт

Результат = Новый Структура("Ключ, Значение");

КонецПроцедуры

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

Параметры: как передавать данные в процедуры и функции

Оба типа подпрограмм поддерживают параметры, которые позволяют передавать данные внутрь блока кода. В 1С:Предприятие параметры могут быть:

  • 📝 По значению (копия данных, изменения не влияют на оригинал)
  • 🔗 По ссылке (работа с оригинальным объектом, изменения сохранятся)
  • 🔄 Знач (оптимизированная передача для сложных типов)

Рассмотрим на примере функции расчета НДС:

Функция РассчитатьНДС(Сумма, Ставка = 20) Экспорт

Возврат Сумма * Ставка / 100;

КонецФункции

Здесь параметр Ставка имеет значение по умолчанию (20), что позволяет вызывать функцию без его указания. А параметр Сумма передается по значению, чтобы избежать случайных изменений исходной переменной.

⚠️ Внимание: При передаче объектов (например, ДокументОбъект) по ссылке без модификатора Знач возможно неожиданное изменение данных в базе. Всегда явно указывайте Знач для параметров-ссылок, если не планируете модифицировать оригинал.

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

Процедура УвеличитьНа10(Перем Число) Экспорт

Число = Число + 10;

КонецПроцедуры

Перем МоеЧисло = 5;

УвеличитьНа10(МоеЧисло);

// Теперь МоеЧисло = 15

Такой подход удобен, но может приводить к трудноотслеживаемым ошибкам, если используется неосторожно.

Область видимости и модификаторы Export, Val, Ref

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

  • 🌍 Глобальные (видимы во всей конфигурации, объявляются в общем модуле с флагом "Глобальный")
  • 📁 Локальные (видимы только в пределах текущего модуля)
  • 🔒 Приватные (видимы только в текущем модуле, если не указан Экспорт)

Модификатор Экспорт делает процедуру или функцию доступной за пределами модуля. Например, в общем модуле:

Функция ПолучитьТекущийКурсВалюты(Валюта) Экспорт

// Логика получения курса

КонецФункции

Без Экспорт эта функция была бы видна только внутри модуля.

Другие важные модификаторы:

  • Val (передача по значению, аналогично отсутствию модификатора)
  • Ref (передача по ссылке, позволяет изменять оригинал)
  • Знач (оптимизированная передача для сложных типов, рекомендуется для объектов)
⚠️ Внимание: В версиях платформы 1С:Предприятие 8.3.18+ появились новые правила контроля типов для параметров с модификатором Знач. Убедитесь, что ваш код соответствует этим правилам, иначе возможны ошибки компиляции.

Практические примеры: когда что использовать

Теория становится понятнее на практике. Рассмотрим типичные сценарии, где целесообразно применять процедуры или функции.

Сценарий 1: Обработка документа

Допустим, нам нужно при проведении документа "РеализацияТоваровУслуг" автоматически резервировать товары на складе. Здесь уместна процедура, так как она изменяет состояние системы:

Процедура ЗарезервироватьТовары(Документ) Экспорт

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

Резерв = Документы.РезервыТоваров.СоздатьДокумент();

Резерв.Товар = Строка.Товар;

Резерв.Количество = Строка.Количество;

Резерв.Записать();

КонецЦикла;

КонецПроцедуры

Сценарий 2: Расчет скидки

А здесь логичнее функция, так как нам нужно получить значение для дальнейшего использования:

Функция РассчитатьСкидку(Клиент, СуммаЗаказа) Экспорт

Если Клиент.Категория = Перечисление.КатегорииКлиентов.ВИП Тогда

Возврат 15;

ИначеЕсли СуммаЗаказа > 10000 Тогда

Возврат 10;

Иначе

Возврат 0;

КонецЕсли;

КонецФункции

Сценарий 3: Валидация данных

Для проверки корректности введенных данных удобно использовать функцию, возвращающую Истина/Ложь:

Функция ПроверитьEmail(Адрес) Экспорт

Возврат СтрНайти(Адрес, "@") > 0 И СтрНайти(Адрес, ".") > 0;

КонецФункции

Нужно ли возвращать значение?|Если да → функция, нет → процедура

Будут ли изменяться внешние данные?|Если да → процедура

Нужно ли использовать результат в выражении?|Если да → функция

Требуется ли оптимизация производительности в цикле?|Если да → процедура-->

Типичные ошибки и как их избегать

Даже опытные разработчики иногда допускают ошибки при работе с процедурами и функциями. Вот наиболее распространенные из них:

  1. Игнорирование модификатора Знач для параметров-ссылок. Это может приводить к неожиданным изменениям в базе данных.
  2. Избыточные глобальные процедуры. Чрезмерное использование глобальных методов усложняет поддержку кода.
  3. Отсутствие обработки ошибок в функциях. Если функция может вернуть некорректное значение, добавьте проверки или используйте Возврат Неопределено.
  4. Длинные списки параметров. Если у функции более 5 параметров, рассмотрите возможность использования структуры.

Пример плохого кода:

// ❌ Антипример: слишком много параметров, нет контроля типов

Функция ОформитьЗаказ(Клиент, Товар1, Количество1, Товар2, Количество2, Доставка, Оплата)

// ...

КонецФункции

Исправленный вариант:

// ✅ Лучше: параметры сгруппированы в структуре

Функция ОформитьЗаказ(ДанныеЗаказа) Экспорт

Если Не ЗначениеЗаполнено(ДанныеЗаказа.Клиент) Тогда

Возврат Неопределено;

КонецЕсли;

// ...

КонецФункции

⚠️ Внимание: В версиях платформы ниже 8.3.15 отсутствует поддержка оператора Неопределено в сигнатуре функций. Для совместимости используйте возврат Null или специальных значений-маркеров.

FAQ: Частые вопросы о процедурах и функциях в 1С

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

Да, оператор Возврат в процедуре прерывает её выполнение, но не возвращает значение. Это удобно для досрочного выхода из цикла или условного блока. Например:

Процедура ОбработатьДокументы(МассивДокументов)

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

Если Док.ПометкаУдаления Тогда

Возврат; // Прерываем процедуру при первом удаленном документе

КонецЕсли;

КонецЦикла;

КонецПроцедуры

Как передать в функцию неопределенное количество параметров?

В 1С:Предприятие нет прямой поддержки переменного числа параметров (как ... в JavaScript), но можно использовать массив:

Функция Суммировать(МассивЧисел) Экспорт

Результат = 0;

Для Каждого Число Из МассивЧисел Цикл

Результат = Результат + Число;

КонецЦикла;

Возврат Результат;

КонецФункции

// Вызов:

Сумма = Суммировать(Новый Массив(1, 2, 3, 4));

В чем разница между Экспорт и глобальными процедурами?

Экспорт делает процедуру или функцию видимой вне текущего модуля, но только в пределах конфигурации. Глобальные процедуры (объявленные в общем модуле с флагом "Глобальный") доступны из любого места, включая внешние обработки и отчеты. Пример:

// В общем модуле "РаботаСКлиентами" с флагом "Глобальный"

Функция ПолучитьБалансКлиента(Клиент) Экспорт

Возврат Клиент.Баланс;

КонецФункции

// Теперь эту функцию можно вызвать даже из внешней обработки:

Баланс = ПолучитьБалансКлиента(ТекущийКлиент);

Как оптимизировать работу функций в циклах?

Если функция вызывается многократно в цикле, рассмотрите следующие оптимизации:

  1. Вынесите неизменяемые вычисления за пределы цикла.
  2. Используйте Знач для передачи объектов, чтобы избежать лишних обращений к базе.
  3. Для простых расчетов замените функцию на локальную переменную, если это возможно.

Пример оптимизации:

// ❌ Неэффективно: функция вызывается для каждой строки

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

Строка.Итог = РассчитатьИтог(Строка.Цена, Строка.Количество);

КонецЦикла;

// ✅ Оптимизировано: вынесение логики в цикл

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

Строка.Итог = Строка.Цена Строка.Количество (1 - Строка.Скидка/100);

КонецЦикла;

Можно ли в 1С создать рекурсивную функцию?

Да, 1С:Предприятие поддерживает рекурсию. Классический пример — вычисление факториала:

Функция Факториал(Число) Экспорт

Если Число = 1 Тогда

Возврат 1;

Иначе

Возврат Число * Факториал(Число - 1);

КонецЕсли;

КонецФункции

Однако будьте осторожны: глубокая рекурсия может привести к переполнению стека. В платформе 8.3.16+ глубина рекурсии ограничена настройкой МаксимальнаяГлубинаРекурсии (по умолчанию 1000).