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