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

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

1С: обращение к процедуре как к функции

Как в 1С обратиться к процедуре как к функции: возврат значения через параметры, преобразование в функцию, примеры кода и типичные ошибки разработчика.

Во встроенном языке 1С процедура и функция — два разных вида методов. Функция возвращает значение через оператор Возврат и может участвовать в выражениях, а процедура только выполняет действия и ничего не возвращает. Поэтому прямой записи вида Результат = МояПроцедура() не существует: попытка присвоить результат вызова процедуры приведёт к ошибке компиляции модуля.

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

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

Чем процедура отличается от функции в 1С

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

Функция объявляется словом Функция, обязана содержать Возврат <значение> и может стоять в правой части присваивания, в условии, в аргументах других методов. Именно возможность участвовать в выражениях и делает функцию пригодной для записи вида Результат = ПолучитьЦену(Номенклатура).

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

Способ 1: вернуть результат через параметр по ссылке

Самый простой приём, когда менять сигнатуру чужой процедуры нельзя или нежелательно, — передать в процедуру переменную, которую она заполнит. В 1С параметры по умолчанию передаются по ссылке, то есть изменения параметра внутри процедуры видны снаружи. Модификатор Знач, наоборот, делает копию и защищает исходную переменную.

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

Если СуммаДокумента > 100000 Тогда

РезультатСкидка = СуммаДокумента * 0.1;

Иначе

РезультатСкидка = 0;

КонецЕсли;

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

// Вызов:

Скидка = 0;

РассчитатьСкидку(СуммаДокумента, Скидка);

// Теперь переменная Скидка содержит результат

Обратите внимание на порядок: сначала объявляется переменная-приёмник, затем процедура вызывается как обычно, и после вызова переменная уже содержит результат. Фактически это и есть «обращение к процедуре как к функции», только результат забирается не из выражения, а из параметра.

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

Способ 2: преобразовать процедуру в функцию

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

Функция РассчитатьСкидку(СуммаДокумента) Экспорт

Если СуммаДокумента > 100000 Тогда

Возврат СуммаДокумента * 0.1;

Иначе

Возврат 0;

КонецЕсли;

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

// Вызов как функция:

Скидка = РассчитатьСкидку(СуммаДокумента);

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

Единственный случай, когда преобразование ломает логику, — если процедура намеренно изменяла несколько параметров по ссылке. Функция возвращает одно значение, поэтому множественные результаты придётся упаковать в структуру или массив.

Как преобразовать процедуру в функцию
  1. 1
    Найдите все вызовы процедуры глобальным поиском по имени
  2. 2
    Замените Процедура/КонецПроцедуры на Функция/КонецФункции
  3. 3
    Добавьте оператор Возврат с результатом во все ветки логики
  4. 4
    Проверьте, что функция возвращает значение на любом пути выполнения
  5. 5
    Выполните синтаксическую проверку модуля и тестовый вызов

Способ 3: функция-обёртка над существующей процедурой

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

Функция ПолучитьСкидку(СуммаДокумента) Экспорт

Скидка = 0;

ТиповойМодуль.РассчитатьСкидку(СуммаДокумента, Скидка);

Возврат Скидка;

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

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

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

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

Способ 4: вернуть несколько значений через структуру

Если от процедуры нужно не одно, а несколько значений, функция может вернуть структуру. Это стандартный приём в 1С для составных результатов.

Функция РассчитатьИтоги(ТаблицаТоваров) Экспорт

Результат = Новый Структура;

Результат.Вставить("Сумма", 0);

Результат.Вставить("СуммаНДС", 0);

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

Результат.Сумма = Результат.Сумма + Строка.Сумма;

Результат.СуммаНДС = Результат.СуммаНДС + Строка.СуммаНДС;

КонецЦикла;

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

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

// Вызов:

Итоги = РассчитатьИтоги(Товары);

Сообщить("Итого: " + Итоги.Сумма);

Альтернатива — вернуть массив, но структура предпочтительнее: обращение по имени ключа (Итоги.СуммаНДС) читается лучше, чем по индексу (Итоги[1]), и не ломается при добавлении новых полей.

Как проверить, что всё работает правильно

После изменения кода выполните синтаксическую проверку модуля (в конфигураторе — через меню «Конфигурация» или сочетание проверки модуля). Компилятор сразу покажет ошибку, если функция не возвращает значение на каком-то пути выполнения или если процедура использована в выражении.

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

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

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

Синтаксическая проверка модуля
Норма

Ошибок нет, все ветки функции содержат Возврат

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

Ошибка о процедуре в выражении или отсутствии возврата

Вызов с типовыми данными
Норма

Переменная-приёмник или результат функции заполнены ожидаемым значением

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

Результат Неопределено или ноль при валидных входных данных

Вызов с пустыми данными
Норма

Функция возвращает осмысленное значение по умолчанию (0, пустую структуру)

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

Исключение или обращение к несуществующему свойству

Типичные ошибки и ограничения

Самая частая ошибка — попытка написать Результат = МояПроцедура() в расчёте на то, что платформа «сама что-нибудь вернёт». Процедура не возвращает значение, и такой код не пройдёт проверку модуля. Вторая ошибка — забыть, что параметр объявлен с Знач, и удивляться пустой переменной после вызова.

Ещё одна ловушка — директивы компиляции. Если процедура объявлена с &НаСервере, а вызов идёт с клиента без права вызова сервера, код упадёт уже в режиме предприятия, а не при проверке. Убедитесь, что контексты вызова и реализации совместимы.

Наконец, при работе с экспортными методами общих модулей помните про флаги модуля: «Сервер», «Вызов сервера», «Клиент (обычное приложение)». Функция-обёртка в модуле с неверными флагами просто не будет видна в нужном контексте.

Типичные ошибки
01
Присваивание результата вызова процедуры — ошибка компиляции, процедуры не участвуют в выражениях
02
Передача переменной-приёмника в параметр с модификатором Знач — переменная остаётся пустой после вызова
03
Правка типовой процедуры вместо обёртки — конфликты при обновлении конфигурации
04
Функция без Возврат в одной из веток — непредсказуемое значение при определённых входных данных
05
Вызов серверной функции из клиентского контекста без флага Вызов сервера — ошибка в режиме предприятия

Что выбрать в вашей ситуации

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

Маршрут решения

Как выбрать подход

Процедура ваша, результат нужен в выраженияхПреобразуйте процедуру в функцию с оператором Возврат
Процедура типовая, менять её нельзяСоздайте функцию-обёртку в собственном общем модуле
Нужно получить несколько значенийВерните структуру с именованными полями или используйте параметры по ссылке
Результат нужен один раз и только для чтенияДостаточно параметра по ссылке без изменения сигнатуры

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

Итог

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

Процедура в 1С не возвращает значение и не может стоять в выражении. Результат получают через параметр по ссылке, преобразование в функцию или функцию-обёртку. Типовой код лучше не менять — обёртка в собственном модуле безопаснее для обновлений.

Частые вопросы

Можно ли вызвать функцию как процедуру, игнорируя результат?

Да, это разрешено: просто напишите вызов без присваивания, например РассчитатьСкидку(Сумма);. Возвращаемое значение будет отброшено. Именно поэтому преобразование процедуры в функцию обычно не ломает существующие вызовы.

Что вернёт функция, если в какой-то ветке нет оператора Возврат?

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

Как передать результат процедуры из модуля объекта в форму?

Объявите в модуле объекта экспортную функцию и вызывайте её из формы через объект. Альтернатива — серверная процедура формы, которая получает объект через РеквизитФормыВЗначение и забирает результат через параметр по ссылке.

Можно ли использовать Выполнить или Вычислить для обхода ограничения?

Технически Вычислить("МояФункция()") работает, но это плохая практика: код не проверяется компилятором, медленнее выполняется и усложняет отладку. Используйте прямые вызовы функций или обёртки.

Чем структура лучше нескольких параметров по ссылке?

Структура делает сигнатуру функции короче и понятнее: один возвращаемый объект с именованными полями вместо пяти-шести параметров-приёмников. Кроме того, состав результата легко расширять, не меняя сигнатуру и не правя все места вызова.