Разработка и Конфигурация · 13 мин
Как писать функции в 1С: руководство для разработчика
Как правильно писать функции в 1С: синтаксис, параметры, возврат значений, экспорт, отличие от процедур. Примеры кода, типичные ошибки и советы разработчику.
Функция во встроенном языке 1С — это именованный блок кода, который принимает параметры, выполняет вычисления и возвращает результат вызывающему коду. Грамотное использование функций делает конфигурацию читаемой, устраняет дублирование логики и упрощает сопровождение: исправление в одном месте автоматически применяется везде, где функция вызывается.
Ошибки при написании функций — неправильная передача параметров, забытый возврат значения, размещение кода не в том модуле — приводят к ошибкам времени выполнения, которые пользователь видит уже в рабочей базе. Поэтому важно понимать не только синтаксис, но и правила размещения функций, область их видимости и отличия от процедур.
Материал рассчитан на разработчиков, которые уже знакомы с конфигуратором 1С и хотят системно разобраться в написании функций: от объявления и параметров до экспорта, директив компиляции и типичных ошибок.
Синтаксис объявления функции
Функция объявляется в модуле между ключевыми словами Функция и КонецФункции. После имени в скобках перечисляются параметры, а тело функции содержит произвольный код на встроенном языке. Результат возвращается оператором Возврат.
Функция РассчитатьСуммуСНДС(Сумма, СтавкаНДС) Экспорт
Если СтавкаНДС = 0 Тогда
Возврат Сумма;
КонецЕсли;
Возврат Сумма + Сумма * СтавкаНДС / 100;
КонецФункции
Имя функции должно быть осмысленным и отражать результат: РассчитатьСуммуСНДС, ПолучитьКурсВалюты, СформироватьТекстЗапроса. Избегайте имён вида Ф1 или ОбработкаДанных — через месяц такой код не поймёт даже автор.
Если оператор Возврат не выполнится ни разу, функция вернёт Неопределено. Это частый источник скрытых ошибок: вызывающий код получает пустое значение вместо ожидаемого числа или строки, и сбой проявляется далеко от места причины.
Чем функция отличается от процедуры
Ключевое различие — возврат значения. Процедура выполняет действия и ничего не возвращает, функция обязана вернуть результат. Поэтому функцию можно вставить прямо в выражение: Итог = РассчитатьСуммуСНДС(База, 20) * Количество;, а процедуру — нет.
Выбор между ними определяется смыслом операции. Если код вычисляет значение (сумму, флаг, найденный элемент справочника) — это функция. Если код выполняет действие (запись документа, отправка письма, вывод сообщения) — процедура. Смешивать обе роли в одной функции — плохая практика: функция с «побочными эффектами» вроде записи в базу усложняет отладку и тестирование.
Функция или процедура
Когда нужен результат вычисления: сумма, найденная ссылка, признак успеха. Возвращает значение через Возврат, используется в выражениях.
Когда нужно действие без результата: запись объекта, вывод сообщения, заполнение таблицы на форме. Не возвращает значение.
Для проверок: ДокументПроведен(), ЕстьПраваДоступа(). Удобно использовать прямо в условии Если.
Параметры: значения по умолчанию и передача по ссылке
Параметры перечисляются через запятую в скобках после имени. Любому параметру можно задать значение по умолчанию — тогда при вызове его можно не указывать:
Функция ПолучитьЦену(Номенклатура, Дата = Неопределено) Экспорт
Если Дата = Неопределено Тогда
Дата = ТекущаяДатаСеанса();
КонецЕсли;
// дальше расчёт цены на дату
КонецФункции
По умолчанию параметры передаются по значению: внутри функции создаётся копия, и изменение параметра не влияет на переменную вызывающего кода. Если добавить ключевое слово Знач — поведение явно закрепляется. Без Знач для изменяемых объектов (структуры, массивы, таблицы значений) фактически передаётся ссылка на объект, и функция может изменить его содержимое. Это удобно для заполнения коллекций, но опасно при неосторожном использовании.
Пропуск параметров при вызове выполняется через запятые: МояФункция(Парам1, , Парам3) — второй параметр получит значение по умолчанию или Неопределено. Однако злоупотреблять пропусками не стоит: вызов с пятью запятыми подряд нечитаем. Если параметров больше трёх-четырёх, лучше передать структуру.
Ключевое слово Экспорт и область видимости
Без слова Экспорт функция доступна только внутри своего модуля. С Экспорт её можно вызывать из других модулей — например, из модуля объекта документа обратиться к функции общего модуля: РаботаСЦенами.ПолучитьЦену(Товар).
Экспортировать следует только те функции, которые действительно нужны снаружи. Вспомогательные «внутренние» функции оставляйте без Экспорт — так проще рефакторить модуль, не опасаясь сломать чужие вызовы. В типовых конфигурациях внутренние функции часто дополнительно помечают комментарием или размещают в области #Область СлужебныеПроцедурыИФункции.
Области видимости по типам модулей: функции модуля формы доступны только этой форме; функции модуля объекта — при работе с конкретным объектом; функции общего модуля с Экспорт — всей конфигурации. Именно общие модули — стандартное место для переиспользуемых функций.
Где размещать функции: общие модули и директивы
Общий модуль — правильное место для функций, которые нужны в нескольких объектах. При создании общего модуля важны флаги в палитре свойств: «Сервер» определяет выполнение на сервере, «Клиент (обычное приложение)» и «Клиент (управляемое приложение)» — на клиенте. Функции, обращающиеся к базе данных (запросы, чтение справочников), должны быть серверными.
Флаг «Вызов сервера» у клиентских общих модулей позволяет клиентскому коду вызывать серверные функции. Без него попытка вызвать серверный модуль с клиента завершится ошибкой. Для привилегированного доступа к данным без проверки прав используется флаг «Привилегированный режим» — применяйте его осознанно, только для служебных операций.
В модулях форм и команд используются директивы компиляции перед объявлением: &НаСервере, &НаКлиенте, &НаСервереБезКонтекста. Функция с директивой &НаСервереБезКонтекста не имеет доступа к данным формы — зато вызывается быстрее, так как не требует передачи всего контекста формы между клиентом и сервером.
- 1Создайте общий модуль с понятным именем, например РаботаСНоменклатурой
- 2В свойствах модуля включите флаг Сервер и при необходимости Вызов сервера
- 3Объявите функцию с ключевым словом Экспорт и осмысленными параметрами
- 4Добавьте проверку входных параметров и оператор Возврат во всех ветках логики
- 5Вызовите функцию из нужного места: ИмяМодуля.ИмяФункции(Параметры)
- 6Проверьте работу в режиме отладки, поставив точку останова внутри функции
Возврат значений и обработка ошибок
Функция может вернуть значение любого типа: число, строку, булево, ссылку на объект, структуру, массив. Для сложных результатов удобна структура — например, функция проверки документа может вернуть структуру с полями «Успех», «ТекстОшибки», «КоличествоОшибок».
Важно, чтобы все ветки логики заканчивались осмысленным возвратом. Типичный узкий момент — функция, которая возвращает значение только при успехе, а при ошибке «проваливается» в конец и возвращает Неопределено. Лучше явно определить поведение: вернуть признак неудачи или вызвать исключение через ВызватьИсключение с понятным текстом.
Функция НайтиДоговорПоНомеру(Номер) Экспорт
Если ПустаяСтрока(Номер) Тогда
ВызватьИсключение "Не передан номер договора";
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1 Договоры.Ссылка
|ИЗ Справочник.ДоговорыКонтрагентов КАК Договоры
|ГДЕ Договоры.Номер = &Номер";
Запрос.УстановитьПараметр("Номер", Номер);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Ссылка;
КонецЕсли;
Возврат Неопределено;
КонецФункции
Конструкция Попытка ... Исключение ... КонецПопытки внутри функции оправдана, когда ошибку можно осмысленно обработать: например, при недоступности внешнего сервиса вернуть пустую структуру и записать событие в журнал регистрации. «Глотать» исключение пустым блоком Исключение — недопустимо: такие ошибки потом ищутся часами.
Типичные ошибки при написании функций
Самая распространённая ошибка — отсутствие Возврат в одной из веток условия. Код компилируется, но при определённых входных данных функция возвращает Неопределено, и ошибка всплывает в вызывающем коде. Проверяйте каждую ветку Если и Иначе.
Вторая группа ошибок — неправильное размещение: серверная функция, вызываемая с клиента без флага «Вызов сервера»; функция с запросом к базе в клиентском модуле формы; обращение к данным формы из метода &НаСервереБезКонтекста. Все они диагностируются ошибками компиляции или выполнения, но новички часто трактуют их неверно.
Третья группа — длинные функции на сотни строк с десятком параметров. Такой код невозможно тестировать. Признак проблемы: функцию трудно назвать одним глаголом. Решение — разбить её на несколько маленьких функций, каждая из которых делает одно действие.
Отладка и проверка функций
Основной инструмент — отладчик конфигуратора. Поставьте точку останова на первой строке функции (F9), запустите отладку (F5) и выполните действие, которое вызывает функцию. По F11 заходите внутрь вызовов, по F10 шагаете построчно, в табло (Shift+F9) проверяйте значения переменных и параметров.
Для быстрой проверки серверных функций удобна консоль кода или внешняя обработка с полем выполнения произвольного кода: можно вызвать функцию с тестовыми параметрами и сразу увидеть результат, не запуская весь сценарий. Перед переносом функции в рабочую базу проверьте её на граничных значениях: пустая строка, Неопределено, нулевое количество, отсутствующая ссылка.
Как проверить результат
Функция возвращает ожидаемый тип при любых входных данных
При части входных данных возвращается Неопределено без явной причины
Понятное исключение с текстом или явный признак неудачи в результате
Исключение проглатывается пустым блоком Исключение
Функция с Экспорт вызывается и работает из всех нужных мест
Ошибка 'не определена' — не хватает Экспорт или флага Вызов сервера
Функция в цикле не выполняет запросы к базе на каждой итерации
Запрос внутри функции вызывается тысячи раз — вынесите данные в одну выборку
FAQ: частые вопросы о функциях в 1С
Чем отличается Знач в параметрах функции?
Ключевое слово Знач перед параметром означает передачу по значению: функция работает с копией и не может изменить переменную вызывающего кода. Без Знач для составных объектов (структуры, массивы) передаётся ссылка, и функция может изменить содержимое объекта. Для примитивных типов (число, строка) разницы практически нет.
Можно ли вызвать функцию до её объявления в модуле?
Да. В пределах одного модуля порядок объявления функций и процедур не важен: компилятор 1С сначала собирает все объявления, а потом выполняет код. Можно вызывать функцию, описанную ниже по тексту модуля.
Как вернуть из функции несколько значений?
Через структуру: создайте Новый Структура с именованными полями, заполните её и верните. Альтернатива — массив, но структура читаемее, так как у значений есть имена. Менять параметры-структуры, переданные в функцию, — работающий, но менее прозрачный приём.
Почему функция в общем модуле не видна из формы?
Проверьте три вещи: есть ли слово Экспорт у функции, включён ли у общего модуля флаг, соответствующий контексту вызова (клиентский или серверный), и включён ли флаг «Вызов сервера», если клиентская форма вызывает серверный модуль. Также убедитесь, что модуль скомпилирован без ошибок — один синтаксический сбой делает недоступным весь модуль.
Нужно ли писать комментарии к функциям?
Да, особенно к экспортным. Стандарт разработки 1С рекомендует описывать назначение функции, параметры и возвращаемое значение в комментарии перед объявлением. Это помогает коллегам и упрощает сопровождение, а в типовых конфигурациях такие комментарии обязательны.
Что лучше: одна большая функция или несколько маленьких?
Несколько маленьких. Функция должна выполнять одну осмысленную операцию и умещаться на экране. Маленькие функции проще тестировать, переиспользовать и отлаживать. Если функция требует прокрутки на несколько экранов и содержит вложенные условия в четыре-пять уровней — её нужно разбивать.
Что важно запомнить
Функция объявляется с параметрами, обязана вернуть значение через Возврат во всех ветках логики и экспортируется словом Экспорт для вызова извне. Переиспользуемые функции размещайте в общих модулях с правильными флагами контекста, проверяйте входные данные и держите функции маленькими — по одной задаче на функцию.