Функции во встроенном языке 1С 8.3: объявление, вызов и место в модулях
Содержание
Функцию в 1С задают блоком Функция Имя(Параметры) … КонецФункции, а результат отдают оператором Возврат Значение;. Чтобы функцию можно было вызвать из другого модуля, после списка параметров пишут слово Экспорт. Всё остальное — где разместить код, как передать параметры и на какой стороне он выполнится — решает, будет ли функция работать так, как вы ждёте.
Типичная боль начинающего программиста 1С: функция написана, синтаксис-контроль молчит, а при вызове из формы — «метод не обнаружен» или параметр внезапно изменился у вызывающего кода. Ниже — синтаксис, правила размещения в модулях, тонкости параметров и рабочий пример для платформы 8.3 в управляемом интерфейсе.
Функция и процедура в 1С: в чём разница
Во встроенном языке 1С есть два вида методов: процедура и функция. Разница одна, но принципиальная.
- 🔹 Процедура выполняет действия и ничего не возвращает. Её вызывают отдельной строкой.
- 🔹 Функция выполняет действия и возвращает значение. Её можно поставить в выражение: присвоить переменной, передать в другой метод, использовать в условии.
| Признак | Процедура | Функция |
|---|---|---|
| Ключевые слова | Процедура … КонецПроцедуры | Функция … КонецФункции |
| Возврат значения | нет, Возврат; только выходит из метода | Возврат Значение; |
| Использование в выражении | нельзя | можно |
| Вызов отдельной строкой | да | да, результат просто отбрасывается |
Функцию допустимо вызвать как процедуру — платформа выполнит её и отбросит результат. Обратное не работает : процедура в выражении даст ошибку уже при синтаксическом контроле модуля.
Если метод что-то вычисляет или проверяет — делайте функцию. Если меняет данные и вызывающему коду нечего сообщить — процедуру. Функция с побочными эффектами (пишет в базу и при этом что-то возвращает) допустима, но имя должно это показывать: ЗаписатьИПолучитьНомер(), а не ПолучитьНомер().
Как объявить функцию в 1С: синтаксис и вызов
Полная форма объявления:
&НаСервере
Функция ИмяФункции(Параметр1, Знач Параметр2, Параметр3 = 0) Экспорт
// тело функции
Результат = Параметр1 + Параметр2 * Параметр3;
Возврат Результат;
КонецФункции
Разберём по частям:
&НаСервере— директива компиляции. Нужна в модулях форм и в общих модулях с несколькими контекстами. В модуле объекта и менеджера её не пишут.Функция— ключевое слово. Регистр не важен, но принято писать с заглавной.ИмяФункции— идентификатор: буквы, цифры, подчёркивание, первым символом не цифра. Пробелы недопустимы.- Список параметров в круглых скобках через запятую. Скобки обязательны даже без параметров:
Функция ТекущийПользовательИмя(). Экспорт— делает функцию доступной снаружи модуля. Без него она видна только внутри своего модуля.Возврат— завершает функцию и отдаёт значение. ОператоровВозвратможет быть несколько, в разных ветках.КонецФункции— закрывает блок. Точку с запятой после него не ставят.
Как вызвать функцию
Внутри того же модуля — просто по имени:
Сумма = ИмяФункции(100, 20, 3); // 100 + 20 * 3 = 160
Из другого модуля — через имя общего модуля или менеджера объекта:
Курс = РаботаСВалютамиСервер.КурсНаДату(Валюта, ТекущаяДатаСеанса());
Остаток = Справочники.Номенклатура.ОстатокПоСкладу(Номенклатура, Склад);
Второй вариант работает, если функция КурсНаДату объявлена с Экспорт в общем модуле, а ОстатокПоСкладу — с Экспорт в модуле менеджера справочника. Имена модулей в примерах условные — подставьте свои.
Что вернёт функция без Возврат
Если выполнение дошло до КонецФункции, не встретив Возврат, функция возвращает Неопределено. Ошибки нет, и это коварно: вызывающий код получит пустое значение и упадёт дальше, в совсем другом месте.
Проверяйте, что каждая ветка Если … ИначеЕсли … Иначе заканчивается Возврат. Надёжный приём — завести переменную Результат в начале, заполнять её по веткам и вернуть одной строкой в конце.
Куда поместить функцию: модуль формы, модуль объекта или общий модуль
Место хранения определяет, кто сможет вызвать функцию и на какой стороне — клиенте или сервере — она выполнится.
| Где лежит функция | Кто вызывает | Когда выбирать |
|---|---|---|
| Модуль формы | только эта форма | работа с реквизитами и элементами формы |
| Модуль объекта | методы этого объекта: ДокументОбъект.Метод() | логика конкретного объекта: заполнение, проверки перед записью |
| Модуль менеджера | Документы.ИмяДокумента.Метод() | действия без открытого объекта: печать, выборки по виду объектов |
| Общий модуль | любой код конфигурации | повторно используемые функции: строки, даты, JSON, обращения к сервисам |
Как создать общий модуль
- В Конфигураторе откройте дерево конфигурации, ветку
Общие → Общие модули. - Правой кнопкой —
Добавить. Задайте имя, напримерОбщегоНазначенияСервер. - В палитре свойств отметьте, где модуль будет компилироваться:
Сервер,Клиент (управляемое приложение),Внешнее соединение. - Если серверные функции модуля должны вызываться с клиента, включите флажок
Вызов сервера. - Откройте модуль, напишите функцию со словом
Экспорт.
Удобно называть модули по суффиксу контекста: …Сервер, …Клиент, …ВызовСервера, …КлиентСервер. Тогда по вызову сразу видно, где выполнится код.
Директивы компиляции в модуле формы
В модуле управляемой формы каждая функция помечается директивой:
- 🖥️
&НаКлиенте— выполняется у пользователя, видит элементы формы, но не может обращаться к базе напрямую. - 🗄️
&НаСервере— выполняется на сервере, получает данные формы, может делать запросы. Вызов передаёт данные формы на сервер и обратно. - ⚡
&НаСервереБезКонтекста— выполняется на сервере без передачи формы. Самый лёгкий серверный вызов: передаются только параметры. - 🔁
&НаКлиентеНаСервереБезКонтекста— компилируется в обоих контекстах; подходит для чистых вычислений без обращения к базе.
Если серверной функции не нужны реквизиты формы, ставьте &НаСервереБезКонтекста. На тонком клиенте и вебе разница в скорости заметна сразу.
Повторное использование возвращаемых значений
У общего модуля есть свойство Повторное использование возвращаемых значений с вариантами На время вызова и На время сеанса. Платформа кэширует результат экспортной функции по набору параметров и при повторном вызове не выполняет код заново.
Это подходит для редко меняющихся данных: настроек, констант, списков ролей. Возвращайте из таких функций фиксированные коллекции — ФиксированнаяСтруктура, ФиксированныйМассив, чтобы вызывающий код случайно не испортил закэшированное значение.
Параметры функции в 1С: по ссылке, Знач и значения по умолчанию
По ссылке — поведение по умолчанию
Без ключевого слова параметр передаётся по ссылке. Если функция присвоит параметру новое значение, оно изменится и у вызывающего кода:
Функция Удвоить(Число)
Число = Число * 2;
Возврат Число;
КонецФункции
А = 5;
Б = Удвоить(А); // Б = 10, и А тоже стало 10
Знач — передача копии
Слово Знач перед параметром передаёт копию значения. Присваивание внутри функции наружу не уходит:
Функция Удвоить(Знач Число)
Число = Число * 2;
Возврат Число;
КонецФункции
А = 5;
Б = Удвоить(А); // Б = 10, А осталось 5
С коллекциями Знач не защищает содержимое. Для массива, структуры или таблицы значений копируется ссылка на объект, а не сам объект. Метод Массив.Добавить() внутри функции изменит исходный массив. Защищает Знач только от присваивания параметру нового объекта.
Нужна независимая копия коллекции — делайте её явно: новый массив с переносом элементов, ТаблицаЗначений.Скопировать(), для структур — новый объект с переносом пар ключ–значение.
Знач при серверных вызовах
При вызове серверной функции с клиента параметры без Знач платформа возвращает обратно на клиент — данные идут по сети дважды. Для серверных функций с клиентским вызовом ставьте Знач у всех параметров, которые функция не должна менять снаружи. Это и меньше трафика, и меньше неожиданных побочных эффектов.
Параметры по умолчанию
Необязательному параметру задают значение после знака =:
Функция ФорматСуммы(Сумма, Валюта = "руб.", ЗнаковПослеЗапятой = 2) Экспорт
ФорматнаяСтрока = "ЧДЦ=" + Формат(ЗнаковПослеЗапятой, "ЧГ=0");
Возврат Формат(Сумма, ФорматнаяСтрока) + " " + Валюта;
КонецФункции
Строка1 = ФорматСуммы(1500); // 1 500,00 руб.
Строка2 = ФорматСуммы(1500, "USD", 0); // 1 500 USD
Строка3 = ФорматСуммы(1500, , 0); // 1 500 руб.
Правила:
- 📌 Значение по умолчанию — только литерал: число, строка, дата,
Истина,Ложь,Неопределено. Выражение или вызов функции подставить нельзя. - 📌 Пропустить параметр из середины можно, оставив пустое место между запятыми, как в
Строка3. - 📌 Переменного числа параметров язык не поддерживает. Если аргументов много или их набор меняется — передавайте одну структуру с настройками.
Пример функции для работы с JSON в 1С
Задача, которая встречается в каждой интеграции: превратить структуру в строку JSON и обратно. С платформы 8.3.6 для этого есть объекты ЗаписьJSON, ЧтениеJSON и методы глобального контекста ЗаписатьJSON(), ПрочитатьJSON().
Создайте серверный общий модуль РаботаСJSON и поместите в него две функции:
// Преобразует структуру, массив или соответствие в строку JSON.
Функция ЗначениеВJSON(Знач Значение) Экспорт
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, Значение);
Возврат Запись.Закрыть();
КонецФункции
// Разбирает строку JSON. При ошибке возвращает Неопределено
// и пишет описание в параметр ТекстОшибки.
Функция JSONВЗначение(Знач ТекстJSON, ТекстОшибки = "", Знач ВСоответствие = Ложь) Экспорт
ТекстОшибки = "";
Если ПустаяСтрока(ТекстJSON) Тогда
ТекстОшибки = "Передана пустая строка";
Возврат Неопределено;
КонецЕсли;
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(ТекстJSON);
Попытка
Результат = ПрочитатьJSON(Чтение, ВСоответствие);
Исключение
ТекстОшибки = ОписаниеОшибки();
Результат = Неопределено;
КонецПопытки;
Чтение.Закрыть();
Возврат Результат;
КонецФункции
Вызов:
Данные = Новый Структура("Номер, Сумма, Оплачен", "А-125", 4800, Истина);
Текст = РаботаСJSON.ЗначениеВJSON(Данные);
// Текст — объект JSON с полями Номер, Сумма, Оплачен
ТекстОшибки = "";
Ответ = РаботаСJSON.JSONВЗначение(Текст, ТекстОшибки);
Если Ответ = Неопределено Тогда
ВызватьИсключение ТекстОшибки;
КонецЕсли;
Сообщить(Ответ.Сумма); // 4800
Что в примере сделано намеренно:
- ✅
ТекстОшибкипередан безЗнач— это выходной параметр, через него функция сообщает причину сбоя. Так функция возвращает и результат, и диагностику. - ✅ Параметр
ВСоответствиепо умолчаниюЛожь, и ответ читается вСтруктура. Если ключи в JSON не подходят под имена 1С — с дефисом, пробелом или начинаются с цифры, напримерorder-id, — передайтеИстина: результат будетСоответствие, где допустимы любые строковые ключи. - ✅
Попытка … Исключениестоит только вокруг разбора, где ошибка ожидаема: невалидный JSON от внешнего сервиса — обычная ситуация.
ЗаписатьJSON() принимает не любые значения. Ссылки на справочники и документы, таблицы значений и соответствия с нестроковыми ключами без настроек сериализации вызовут исключение. Перед записью переложите данные в структуры и массивы из примитивов: строк, чисел, дат, булевых.
Как сделать функцию быстрой и понятной
Функцию читают чаще, чем пишут. Производительность в 1С чаще всего теряется не в вычислениях, а в лишних обращениях к базе и серверу.
Производительность
- 🚀 Нет запросам в цикле. Сто вызовов функции, каждый с запросом по одной ссылке, — это сто запросов. Передайте в функцию массив ссылок и сделайте один запрос с условием
В (&Ссылки). - 🚀 Нет серверным вызовам в цикле на клиенте. Каждый вызов — сетевой обмен. Соберите данные и вызовите сервер один раз.
- 🚀 Не открывайте объект ради одного реквизита.
Ссылка.ПолучитьОбъект()читает объект целиком с табличными частями. Для одного-двух полей хватит запроса или функции БСПОбщегоНазначения.ЗначениеРеквизитаОбъекта(), если библиотека есть в конфигурации. - 🚀 Ранний выход. Проверьте входные параметры в начале и сразу верните результат, если работать не с чем. Меньше вложенных
Если, меньше лишней работы. - 🚀 Кэш для неизменных данных — через модуль с повторным использованием значений, описанный выше.
Читаемость
- 📖 Имя начинается с глагола или отвечает на вопрос:
ПолучитьКурс,ЭтоОрганизацияПлательщикНДС,СуммаПрописью. - 📖 Одна функция — одна задача. Если в имени просится «И», функцию стоит разделить.
- 📖 Перед экспортной функцией — комментарий с описанием параметров и возвращаемого значения. Конфигуратор и EDT показывают его во всплывающей подсказке при наборе.
- 📖 Экспортные функции общих модулей группируют в области
#Область ПрограммныйИнтерфейс … #КонецОбласти, служебные — вСлужебныеПроцедурыИФункции.
Шаблон комментария, который понимает контекстная подсказка:
// Возвращает сумму документа с учётом скидки.
//
// Параметры:
// Сумма - Число - сумма до скидки.
// Процент - Число - процент скидки, от 0 до 100.
//
// Возвращаемое значение:
// Число - сумма после скидки, округлённая до копеек.
//
Функция СуммаСоСкидкой(Знач Сумма, Знач Процент = 0) Экспорт
Возврат Окр(Сумма * (100 - Процент) / 100, 2);
КонецФункции
Проверка: СуммаСоСкидкой(1250, 12) даёт 1250 × 88 / 100 = 1100.
Ошибки при написании функций в 1С и как их найти
Ещё одна ловушка, которую не ловит синтаксический контроль, — рекурсия без надёжного условия выхода. Рекурсия в 1С разрешена, но функция обхода иерархии, которая наткнётся на зацикленные данные (элемент ссылается сам на себя через цепочку родителей), будет вызывать себя до исчерпания стека. Добавьте ограничение глубины или храните уже пройденные ссылки в соответствии и пропускайте их.
Для отладки поставьте точку останова (F9) на первую строку функции и войдите в неё по F11. В окне Локальные видны значения всех параметров, а окно вычисления выражения (Shift+F9) покажет значение любого выражения прямо в контексте функции.
Частые вопросы о функциях в 1С
Как вернуть из функции несколько значений?
Возврат Новый Структура("Сумма, НДС", Сумма, НДС);. Другой путь — выходные параметры без Знач, но структура читается проще.Можно ли объявить функцию внутри другой функции?
Как вызвать функцию по имени, записанному в строке?
Вычислить("ИмяМодуля.ИмяФункции(Параметр)"). Имя должно приходить только из вашего кода, а не от пользователя: иначе через Вычислить можно выполнить произвольный код.