Как читать код 1С: значение знаков, ключевых слов и инструкций препроцессора
Содержание
В коде 1С знак & перед процедурой означает директиву компиляции (где выполнится метод), # — инструкцию препроцессора (#Если, #Область), ~ — метку для оператора Перейти, | — продолжение многострочной строки, а ?(...) — условное выражение, аналог тернарного оператора. Внутри текста запроса тот же & уже означает параметр: &Контрагент.
Остальное расшифровать проще: встроенный язык 1С:Предприятия 8.3 построен на русских ключевых словах, и почти каждое слово читается буквально. Ниже — справочник по символам, операторам и конструкциям, которые встречаются в типовых конфигурациях, и построчный разбор реального фрагмента.
Арифметика, присваивание и сравнение в языке 1С
Операторов в 1С немного, и все они знакомы по школьной математике. Сложность в другом: один и тот же знак ведёт себя по-разному в зависимости от типа значений.
| Знак | Что делает | Пример | Результат |
|---|---|---|---|
+ | сложение чисел, склейка строк, сдвиг даты | 10 + 5 | 15 |
- | вычитание, разница дат | '20240131' - '20240101' | 2592000 (секунды) |
* | умножение | 7 * 3 | 21 |
/ | деление | 10 / 4 | 2.5 |
% | остаток от деления | 10 % 3 | 1 |
= | присваивание или проверка равенства | А = 5; | А теперь 5 |
<> | не равно | А <> 0 | Истина или Ложь |
< > <= >= | сравнение чисел, строк, дат | Дата1 < Дата2 | Истина или Ложь |
Один знак = на две роли
В 1С нет отдельного ==. Знак = в начале инструкции — присваивание: Сумма = 100;. Внутри Если, Пока или справа от другого = — сравнение: ЕстьДолг = Сумма = 0; записывает в ЕстьДолг результат проверки.
Составных операторов вроде += или ++ в языке нет. Пишут полностью: Счетчик = Счетчик + 1;.
Как складываются разные типы
Тип результата определяет левый операнд:
- 🔤
"5" + 3даёт строку"53": число приводится к строке; - 🔢
3 + "5"даёт число8: строка приводится к числу, а если не получится — ошибка «Преобразование значения к типу Число не может быть выполнено»; - 📅
ТекущаяДата() + 86400— та же дата через сутки: к дате прибавляются секунды; - ⏱ разность двух дат — число секунд. Из примера в таблице: 2 592 000 / 86 400 = 30 дней.
Склеивая число со строкой через +, вы получите число с разделителем разрядов: "Итого: " + 1500 выдаст Итого: 1 500 с неразрывным пробелом. Для чисел в кодах и номерах используйте Формат(Число, "ЧГ=0").
Деление на ноль вызывает исключение «Деление на 0», а не возвращает бесконечность. Перед делением проверяйте знаменатель.
Логические операции и условное выражение ?()
Логических операций три: И, ИЛИ, НЕ. Приоритет от высокого к низкому: НЕ, затем И, затем ИЛИ. Поэтому А ИЛИ Б И В читается как А ИЛИ (Б И В). Скобки снимают все сомнения и читаются быстрее.
Сокращённое вычисление
1С не вычисляет правую часть, если результат уже ясен по левой. На этом построен частый приём защиты от ошибки:
Если Документ <> Неопределено И Документ.Проведен Тогда
// обращение к Документ.Проведен выполнится,
// только если Документ заполнен
КонецЕсли;
Если поменять условия местами, при пустом Документ получите ошибку «Поле объекта не обнаружено».
Тернарный оператор ?()
Условное выражение записывается как функция с вопросительным знаком:
Статус = ?(Остаток > 0, "Есть долг", "Расчёты закрыты");
Первый аргумент — условие, второй — значение при Истина, третий — при Ложь. Конструкции можно вкладывать, но после второго уровня код становится нечитаемым: лучше обычный Если ... ИначеЕсли ... КонецЕсли.
💡 Слово Не в начале условия часто пишут с заглавной и строчными буквами: Если Не ЗначениеЗаполнено(Объект.Склад) Тогда. Регистр в ключевых словах роли не играет: НЕ, Не и не равнозначны.
Знаки &, ~, |, # и другие символы в коде 1С
Эти символы сбивают с толку чаще всего, потому что в других языках они значат совсем другое.
| Символ | Где встречается | Значение |
|---|---|---|
& перед методом | модули форм, команд | директива компиляции: &НаКлиенте, &НаСервере |
& перед методом в расширении | модули расширений | аннотация: &Перед, &После, &Вместо, &ИзменениеИКонтроль |
& в тексте запроса | Запрос.Текст | параметр запроса: ГДЕ Дата > &НачалоПериода |
~ | перед именем | метка для Перейти |
| | в начале строки внутри кавычек | продолжение многострочного строкового литерала |
# | в начале строки | инструкция препроцессора |
// | где угодно | комментарий до конца строки |
; | конец инструкции | разделитель операторов |
"" | внутри строки | одна кавычка: "Тип ""Б""" даёт Тип "Б" |
'...' | одинарные кавычки | литерал даты: '20240115', '20240115103000' |
. | после имени | обращение к свойству или методу |
[ ] | после коллекции | обращение по индексу или ключу: Массив[0], Структура["Сумма"] |
Директивы компиляции &
В модуле управляемой формы каждая процедура помечена, где ей выполняться:
- 🖥
&НаКлиенте— на компьютере пользователя, без прямого доступа к базе; - 🗄
&НаСервере— на сервере, с данными формы; - ⚡
&НаСервереБезКонтекста— на сервере без передачи формы: быстрее, но реквизиты формы недоступны; - 🔁
&НаКлиентеНаСервереБезКонтекста— метод можно вызвать и там, и там.
Метод в модуле формы без директивы компилируется на сервере. Отсюда частая ошибка новичков: процедура «не видна» из клиентского обработчика, потому что директиву забыли.
Аннотации в расширениях
В расширении конфигурации & перед процедурой говорит, как она соотносится с типовой. &Перед("ПередЗаписью") выполнится до типового метода, &После — после, &Вместо — заменит его. &ИзменениеИКонтроль копирует тело типового метода и позволяет внутри пометить правки инструкциями #Вставка ... #КонецВставки и #Удаление ... #КонецУдаления. Если после обновления типовой код изменился, платформа сообщит об этом при проверке расширения.
Символ @
В синтаксисе встроенного языка у @ нет значения. Вы увидите его только внутри комментариев: так подавляют предупреждения средств проверки кода, например в 1C:EDT. На выполнение программы такие строки не влияют.
Инструкции препроцессора: #Если и #Область
Строки, начинающиеся с #, обрабатываются до компиляции. Они решают, какой код вообще попадёт в модуль, или просто размечают его.
#Если ... #КонецЕсли
Отсекают код по месту выполнения:
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
// код модуля объекта, который не должен попасть на тонкий клиент
#Иначе
ВызватьИсключение "Недопустимый вызов объекта на клиенте.";
#КонецЕсли
Это начало модуля менеджера или объекта во многих типовых конфигурациях. Символы препроцессора, которые встречаются чаще всего:
Сервер,НаСервере,Клиент,НаКлиенте;ТонкийКлиент,ВебКлиент;ТолстыйКлиентОбычноеПриложение,ТолстыйКлиентУправляемоеПриложение;ВнешнееСоединение;МобильноеПриложениеКлиент,МобильноеПриложениеСервер.
Между ними допустимы И, Или, Не, а ветки — #ИначеЕсли и #Иначе.
#Область ... #КонецОбласти
Области на выполнение не влияют вовсе. Это разметка для сворачивания блоков в Конфигураторе и для порядка в модуле. В типовых решениях на БСП встречаются стандартные имена: ПрограммныйИнтерфейс, СлужебныйПрограммныйИнтерфейс, ОбработчикиСобытий, СлужебныеПроцедурыИФункции. Имя области пишется одним словом, без пробелов.
Свернуть все области в Конфигураторе можно через контекстное меню модуля, пункт со словом «Свернуть». Это первое, что стоит сделать в длинном общем модуле: видна структура, а не 5 000 строк подряд.
Ключевые слова встроенного языка: Новый, Выполнить, Продолжить и другие
Ключевое слово — зарезервированное имя, которое нельзя использовать как переменную. Их несколько десятков, вот те, что вызывают вопросы.
| Слово | Значение | Пример |
|---|---|---|
Новый | создать объект встроенного типа | Массив = Новый Массив; |
Перем | объявить переменную | Перем мКэшЦен; |
Экспорт | сделать метод или переменную доступными извне модуля | Функция ЦенаТовара(Товар) Экспорт |
Знач | передать параметр по значению | Процедура Пересчет(Знач Сумма) |
Возврат | выйти из метода, в функции — вернуть значение | Возврат Итог; |
Прервать | досрочно выйти из цикла | — |
Продолжить | перейти к следующему шагу цикла | — |
Попытка ... Исключение ... КонецПопытки | перехват ошибок | см. ниже |
ВызватьИсключение | сгенерировать ошибку | ВызватьИсключение "Не указан склад"; |
Неопределено, Null | пустые значения | Если Значение = Неопределено Тогда |
Истина, Ложь | логические константы | — |
Знач и передача по ссылке
По умолчанию параметр передаётся по ссылке: если процедура изменит Сумма, изменится и переменная у вызывающего кода. Знач создаёт копию. Для коллекций копируется только ссылка: строки в переданную таблицу значений добавятся и с Знач.
Неопределено и Null — не одно и то же
Неопределено — значение необъявленной или незаполненной переменной. Null приходит из запросов: например, при левом соединении, когда справа нет записи. Null + 5 вызовет ошибку, поэтому в запросах суммы оборачивают в ЕСТЬNULL(Поле, 0).
Выполнить и Вычислить
Выполнить(Строка) исполняет текст как код, Вычислить(Строка) возвращает значение выражения. Так типовые конфигурации иногда вызывают методы по имени, полученному из настроек.
Выполнять строку, пришедшую от пользователя или из внешнего файла, нельзя без безопасного режима — это прямая дорога к выполнению чужого кода. Перед вызовом включают УстановитьБезопасныйРежим(Истина).
Редкие конструкции, которые путают даже опытных
Эти записи встречаются в старых модулях, в обработках сторонних разработчиков и в новых релизах платформы.
Метка и Перейти
Для Каждого Строка Из Товары Цикл
Если Строка.Количество = 0 Тогда
Перейти ~Пропуск;
КонецЕсли;
// обработка строки
~Пропуск:
КонецЦикла;
~Пропуск: объявляет метку (с двоеточием), Перейти ~Пропуск; переходит к ней. В современном коде вместо этого пишут Продолжить. Метка внутри цикла — признак кода, перенесённого из 1С 7.7.
Многострочная строка через |
Текст = "Первая строка
|Вторая строка
|Третья строка";
Каждое продолжение начинается с вертикальной черты. Так оформлены все тексты запросов в типовых конфигурациях.
Повторный выброс ошибки
ВызватьИсключение; без текста внутри блока Исключение пробрасывает ту же ошибку дальше, сохранив её описание. Это не опечатка, а способ записать лог и не «проглотить» сбой.
Асинхронные методы: Асинх и Ждать
С платформы 8.3.18 появились асинхронные функции:
&НаКлиенте
Асинх Процедура Удалить(Команда)
Ответ = Ждать ВопросАсинх("Удалить строку?", РежимДиалогаВопрос.ДаНет);
Если Ответ = КодВозвратаДиалога.Да Тогда
// удаление
КонецЕсли;
КонецПроцедуры
Ждать приостанавливает процедуру, пока пользователь не ответит, без блокирующего модального окна. В коде до 8.3.18 ту же задачу решают через Новый ОписаниеОповещения и отдельную процедуру-обработчик ответа.
ДобавитьОбработчик
ДобавитьОбработчик Объект.Событие, ИмяПроцедуры; подписывает процедуру на событие объекта во время выполнения. Встречается редко, в основном при работе с внешними COM-объектами. Отписка — УдалитьОбработчик.
Разбор фрагмента кода построчно
Возьмём типичный обработчик команды формы документа: он считает сумму продаж контрагенту и пишет её в комментарий.
&НаКлиенте
Процедура ПосчитатьПродажи(Команда)
Если Не ЗначениеЗаполнено(Объект.Контрагент) Тогда
Сообщить("Укажите контрагента");
Возврат;
КонецЕсли;
ПосчитатьПродажиНаСервере();
КонецПроцедуры
&НаСервере
Процедура ПосчитатьПродажиНаСервере()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(СУММА(Продажи.СуммаДокумента), 0) КАК Сумма
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Продажи
|ГДЕ
| Продажи.Контрагент = &Контрагент
| И Продажи.Проведен";
Запрос.УстановитьПараметр("Контрагент", Объект.Контрагент);
Выборка = Запрос.Выполнить().Выбрать();
Итого = ?(Выборка.Следующий(), Выборка.Сумма, 0);
Объект.Комментарий = СтрШаблон("Продажи: %1 руб.", Формат(Итого, "ЧДЦ=2"));
КонецПроцедуры
Что здесь происходит:
&НаКлиенте— первая процедура выполняется у пользователя. ПараметрКомандаплатформа передаёт сама.Если Не ЗначениеЗаполнено(...)— проверка, что контрагент выбран.Возвратпрерывает процедуру, если нет.- Вызов
ПосчитатьПродажиНаСервере()— переход с клиента на сервер. Иначе к базе не обратиться. &НаСервере— серверный метод. Данные формы, включаяОбъект, доступны.Новый Запроссоздаёт объект запроса.- Текст запроса — многострочная строка: каждая строка после первой начинается с
|. &Контрагентвнутри текста — параметр. Его значение задаётУстановитьПараметрс тем же именем, но уже без&.ЕСТЬNULL(..., 0)— если продаж нет, сумма вернётся нулём, а неNull.Запрос.Выполнить().Выбрать()— цепочка вызовов через точку: выполнить запрос и получить выборку.?(Выборка.Следующий(), Выборка.Сумма, 0)— тернарный оператор: если строка есть, берём сумму, иначе 0.СтрШаблонподставляет значение на место%1,Формат(Итого, "ЧДЦ=2")оставляет 2 знака после запятой.
Читать незнакомый модуль удобнее в таком же порядке: сначала директивы и границы процедур, затем условия выхода, затем вызовы других методов. Переход к определению метода в Конфигураторе — клавиша F12 на его имени.
Ошибки при чтении и правке чужого кода
Ниже то, на чём спотыкаются, когда впервые разбирают код типовой конфигурации:
- ❌ Путают
&в коде и в запросе. Перед процедурой это директива, внутри строки запроса — параметр. Удалите&из текста запроса, и платформа будет искать поле с таким именем. - ❌ Считают
#Областьусловием. Область ничего не включает и не выключает. Код внутри неё выполняется всегда. - ❌ Ждут, что
=вЕслиприсвоит значение. Внутри условия это только сравнение, переменная не изменится. - ❌ Удаляют
|, переформатируя запрос. Без вертикальной черты строковый литерал оборвётся, и модуль не скомпилируется. - ❌ Правят типовой модуль напрямую. При следующем обновлении правки придётся переносить вручную. Изменения безопаснее делать в расширении с аннотациями
&Перед,&Послеили&ИзменениеИКонтроль.
Частые вопросы
Чем отличается процедура от функции в 1С?
Возврат Значение; и может стоять справа от =. Процедура ничего не возвращает, Возврат; в ней просто завершает выполнение.Можно ли писать код 1С латиницей?
Если — If, Процедура — Procedure, Новый — New. В одном модуле можно смешивать оба варианта, но в типовых конфигурациях принят русский.Почему в коде встречаются переменные с приставкой «м»?
Перем в его начале. Платформа приставку не учитывает.Где посмотреть описание любого метода прямо в Конфигураторе?
Ctrl+F1 — откроется синтакс-помощник с описанием параметров и примерами. Сам синтакс-помощник открывается и из меню Справка.Есть ли в языке 1С многострочные комментарии?
//. Чтобы закомментировать блок, выделите строки и воспользуйтесь командой блочного комментирования в контекстном меню модуля.