Объявление функций в 1С:Предприятие 8.3

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

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

Базовый синтаксис объявления функции в 1С

В 1С:Предприятие 8.3 функция объявляется с помощью конструкции Функция, за которой следует имя, список параметров в круглых скобках и тело функции. Минимальный рабочий пример выглядит так:

Функция ПримерПростойФункции()

Возврат 42;

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

Разберём элементы синтаксиса:

  • 🔹 Ключевое слово Функция — обязательный маркер начала объявления. Без него система воспримет код как процедуру или вызовет ошибку.
  • 🔹 Имя функции — должно быть уникальным в пределах модуля. Рекомендуется использовать осмысленные названия (например, РассчитатьСкидку вместо Функция1).
  • 🔹 Список параметров — перечисляется в круглых скобках через запятую. Может быть пустым, если параметры не требуются.
  • 🔹 Тело функции — блок кода, выполняемый при вызове. Обязательно должен содержать оператор Возврат (иначе функция вернёт Неопределено).
  • 🔹 Ключевое слово КонецФункции — закрывает объявление. Его отсутствие приведёт к синтаксической ошибке.

Важно: в отличие от процедур, функции всегда возвращают значение. Если явного оператора Возврат нет, результат будет Неопределено, что может привести к логическим ошибкам в коде. Например, при проверке условия Если МояФункция() Тогда условие выполнится, только если функция вернёт Истина — в остальных случаях (включая Неопределено) результат будет Ложь.

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

Параметры функции: обязательные и необязательные

Параметры позволяют передавать данные в функцию для обработки. В они делятся на два типа:

  • 🔴 Обязательные — должны быть переданы при вызове. Их отсутствие вызовет ошибку выполнения.
  • 🟢 Необязательные — могут быть опущены. Для них указывается значение по умолчанию.

Пример функции с обоими типами параметров:

Функция РассчитатьСтоимость(Количество, Цена, Скидка = 0)

Возврат Количество Цена (1 - Скидка / 100);

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

Здесь Количество и Цена — обязательные параметры, а Скидка — необязательный (по умолчанию равен 0). Вызов функции может выглядеть так:

Сумма = РассчитатьСтоимость(10, 1000); // Скидка = 0

СуммаСоСкидкой = РассчитатьСтоимость(10, 1000, 15); // Скидка = 15%

Особенности работы с параметрами:

  • 📌 Необязательные параметры должны идти после обязательных. Иначе компилятор выдаст ошибку.
  • 📌 Значение по умолчанию может быть константой (число, строка, Истина/Ложь) или выражением, но не переменной.
  • 📌 При передаче параметров по значению (по умолчанию) изменения внутри функции не затрагивают исходные данные. Для изменения оригинальных переменных используйте передачу по ссылке (ключевое слово Перем).
💡

Если функция принимает много параметров (5+), рассмотрите возможность использования структуры вместо списка. Это упростит вызов и поддержку кода. Пример: Функция ОбработатьДанные(Параметры) Экспорт, где Параметры — структура с полями.

Ключевое слово Экспорт: когда и зачем использовать

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

  • 🔄 Внешних обработок и отчётов — экспортированные функции можно вызывать из других модулей.
  • 🔄 Общих модулей — функции с Экспорт становятся доступны глобально (если модуль помечен как Глобальный).
  • 🔄 Интеграции — экспортированные функции можно вызывать через COM-соединение или HTTP-сервисы.

Пример объявления экспортируемой функции:

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

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ Курс

ИЗ РегистрСведений.КурсыВалют

ГДЕ Валюта = &Валюта И Дата = &Дата";

Запрос.УстановитьПараметр("Валюта", Валюта);

Запрос.УстановитьПараметр("Дата", Дата);

Результат = Запрос.Выполнить().Выбрать().Следующий();

Если Результат = Неопределено Тогда

Возврат 0;

Иначе

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

КонецЕсли;

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

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

⚠️ Внимание: Избыточное использование Экспорт увеличивает риск конфликтов имён и усложняет поддержку кода. Экспортируйте только те функции, которые действительно нужны вне текущего модуля.

Разница между функциями и процедурами в 1С

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

Критерий Функция Процедура
Возврат значения Обязателен (через Возврат) Отсутствует
Использование в выражениях Можно использовать в условиях, присваиваниях (например, Если МояФункция() Тогда) Только как отдельный оператор (например, МояПроцедура();)
Синтаксис объявления Функция Имя() ... КонецФункции Процедура Имя() ... КонецПроцедуры
Типичное применение Расчёты, проверки, получение данных Изменение состояния (запись в базу, вывод сообщений)

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

  • 🔹 Функция — если нужно получить результат (например, рассчитать сумму, проверить условие, преобразовать данные).
  • 🔹 Процедура — если нужно выполнить действие без возврата значения (например, отправить письмо, обновить запись в базе, показать сообщение пользователю).

Пример некорректного использования процедуры вместо функции:

// Плохо: процедура не возвращает результат

Процедура ПолучитьСтавкуНДС()

Ставка = 20;

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

// Хорошо: функция возвращает значение

Функция ПолучитьСтавкуНДС()

Возврат 20;

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

💡

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

Типичные ошибки при объявлении функций и как их избежать

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

  1. Отсутствие оператора Возврат

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

    Если МояФункция() Тогда // Вернёт Ложь, если функция не возвращает Истина
    

    // Код не выполнится, даже если логика функции подразумевала возвращение Истина

    ⚠️ Внимание: Всегда проверяйте, что функция возвращает ожидаемый тип данных. Например, если вы рассчитываете число, а функция возвращает строку, это вызовет ошибку при математических операциях.
  2. Неправильная передача параметров по ссылке

    Если вы хотите изменить оригинальную переменную внутри функции, используйте ключевое слово Перем:

    Функция УвеличитьЗначение(Перем Число)
    

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

    Возврат Число;

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

    Без Перем изменения затрагивают только локальную копию параметра.

  3. Игнорирование типов параметров
    — слабо типизированный язык, но это не означает, что типы можно игнорировать. Например, если функция ожидает число, а вы передаёте строку, это вызовет ошибку:
    Функция Умножить(А, Б)
    

    Возврат А * Б;

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

    // Ошибка: нельзя умножать строку на число

    Результат = Умножить("10", 2);

Чтобы избежать ошибок, следуйте чек-листу:

☑️ Проверка функции перед использованием

Выполнено: 0 / 4

Практические примеры: функции для реальных задач

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

1. Проверка заполненности реквизитов

Функция проверяет, заполнены ли обязательные реквизиты документа или справочника:

Функция ПроверитьЗаполненность(Объект, СписокРеквизитов) Экспорт

Для Каждого Реквизит Из СписокРеквизитов Цикл

Если ЗначениеЗаполнено(Объект[Реквизит]) = Ложь Тогда

Возврат Ложь;

КонецЕсли;

КонецЦикла;

Возврат Истина;

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

// Пример использования:

Реквизиты = Новый Массив;

Реквизиты.Добавить("Контрагент");

Реквизиты.Добавить("СуммаДокумента");

Если ПроверитьЗаполненность(ТекущийДокумент, Реквизиты) = Ложь Тогда

Предупреждение("Не заполнены обязательные реквизиты!");

КонецЕсли;

2. Форматирование чисел

Функция преобразует число в строку с разделителями разрядов:

Функция ФорматироватьЧисло(Число, Разделитель = " ") Экспорт

Если ТипЗнч(Число) <> Тип("Число") Тогда

Возврат "";

КонецЕсли;

СтроковоеЧисло = Формат(Число, "ЧГ=0");

Возврат СтрЗаменить(СтроковоеЧисло, ",", Разделитель);

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

// Пример: ФорматироватьЧисло(1000000) вернёт "1 000 000"

3. Поиск дублей в справочнике

Функция ищет дублирующиеся элементы по заданному реквизиту:

Функция НайтиДублиПоРеквизиту(Справочник, Реквизит) Экспорт

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ

| " + Реквизит + " КАК Значение,

| КОЛИЧЕСТВО(*) КАК Количество

|ИЗ

| " + Справочник + " КАК Справочник

|СГРУППИРОВАТЬ ПО

| " + Реквизит + "

|ИМЕЮЩИЕ

| КОЛИЧЕСТВО(*) > 1";

Результат = Запрос.Выполнить().Выбрать();

Дубли = Новый Массив;

Пока Результат.Следующий() Цикл

Дубли.Добавить(Результат.Значение);

КонецЦикла;

Возврат Дубли;

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

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

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

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

Оптимизация и производительность функций

Плохо написанные функции могут стать узким местом в производительности . Следующие рекомендации помогут оптимизировать код:

  • 🚀 Избегайте рекурсии — в рекурсивные функции потребляют много памяти и могут привести к переполнению стека. Например, для обхода дерева справочников лучше использовать цикл.
  • 🚀 Минимизируйте обращения к базе — если функция часто вызывает запросы, кешируйте результаты в статических переменных или используйте временные таблицы.
  • 🚀 Используйте типизированные коллекции — вместо универсального Массив выбирайте СписокЗначений, Соответствие или Структура в зависимости от задачи.
  • 🚀 Ограничивайте область видимости — не экспортируйте функции без необходимости. Локальные функции работают быстрее.

Пример оптимизированной функции для поиска элемента в справочнике:

Функция НайтиЭлементПоНаименованию(Справочник, Наименование)

// Кешируем результат для повторных вызовов

Статическая Кеш = Новый Соответствие;

Если Кеш.Содержит(Наименование) Тогда

Возврат Кеш[Наименование];

КонецЕсли;

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1 Ссылка

ИЗ " + Справочник + "

ГДЕ Наименование = &Наименование";

Запрос.УстановитьПараметр("Наименование", Наименование);

Результат = Запрос.Выполнить().Выбрать().Следующий();

Если Результат = Неопределено Тогда

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

Иначе

Кеш.Вставить(Наименование, Результат.Ссылка);

Возврат Результат.Ссылка;

КонецЕсли;

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

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

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

Можно ли объявить функцию внутри другой функции?

Нет, не поддерживает вложенные функции. Все функции должны объявляться на уровне модуля. Однако вы можете использовать локальные процедуры внутри функции для структурирования кода.

Как вернуть из функции несколько значений?

В функция может возвращать только одно значение. Чтобы передать несколько результатов, используйте:

  • 📦 СтруктуруВозврат Новый Структура("Поле1, Поле2", Значение1, Значение2);
  • 📦 МассивВозврат Новый Массив(Значение1, Значение2);
  • 📦 Соответствие — если нужно вернуть пары "ключ-значение".
Что будет, если не указать КонецФункции?

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

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

В нет прямой поддержки переменного числа параметров (как ... в других языках). Альтернативы:

  • 🔢 Использовать массивФункция МояФункция(Параметры) Экспорт, где Параметры — массив значений.
  • 🔢 Передавать структуру с именованными параметрами.
Можно ли переименовать функцию без последствий?

Если функция используется в других модулях или в базе данных (например, в обработках или отчётах), её переименование приведёт к ошибкам. Перед переименованием:

  1. Проверьте все места вызова функции (можно использовать поиск по коду в конфигураторе).
  2. Обновите все ссылки на неё.
  3. Протестируйте работу системы после изменений.

Для критичных функций лучше создать новую с нужным именем и пометить старую как Устаревшая (с выводом предупреждения при вызове).