Операторы встроенного языка 1С:Предприятие 8.3 — от присваивания до Попытки
Содержание
Оператор в языке 1С — это одна законченная инструкция модуля: присвоить значение, проверить условие, повторить действие в цикле, перехватить ошибку. Операторы отделяются друг от друга точкой с запятой ;, а внутри них работают операции — +, =, И, ?() и другие.
Путаница начинается, когда новичок читает чужой код: = то присваивает, то сравнивает, НЕ срабатывает не там, где ожидалось, а Попытка молча глотает ошибку. Разберём каждый вид операторов 1С с примерами кода, таблицей приоритетов и типовыми ловушками. Всё сказанное относится к платформе 8.3 и одинаково для любой конфигурации — Бухгалтерии, ЗУП, УТ или своей разработки.
Оператор 1С: определение и правила записи
В документации платформы встроенный язык делится на два уровня:
- 🧩 операторы — то, что выполняется:
Если,Для,Пока,Попытка,Возврат, присваивание, вызов процедуры; - ➕ операции — то, что вычисляет значение внутри выражения: арифметика, сравнение, логика.
В разговоре оба понятия часто называют «операторами», и это нормально. Главное — понимать разницу: А + Б само по себе ничего не делает, а Сумма = А + Б; уже оператор.
Правила синтаксиса, которые стоит помнить
- Каждый оператор заканчивается
;. Перед ключевыми словамиКонецЕсли,КонецЦикла,Иначе,Исключениеточку с запятой у последнего оператора можно опустить — компилятор не ругается. Но по стандартам разработки её лучше ставить всегда. - Регистр букв не важен:
ЕСЛИ,еслииЕсли— одно и то же. То же с именами переменных. - Почти у каждого ключевого слова есть английский вариант:
Если—If,Цикл—Do,Попытка—Try. Смешивать языки в одном модуле можно, но читать такой код тяжело. - Один оператор можно растянуть на несколько строк — перенос строки не завершает его. Завершает только
;. - Комментарий начинается с
//и идёт до конца строки. Блочных комментариев нет.
// Один оператор на три строки — это корректно
ИтогоКОплате = СуммаДокумента
+ СуммаДоставки
- СуммаСкидки;
Если строковая константа не помещается в строку, продолжите её с новой строки символом |. Кавычку внутри строки удваивают: "Ошибка ""деления""".
Присваивание и операции в выражениях
Оператор присваивания
Присваивание записывается одним знаком =: слева переменная или свойство, справа выражение.
Количество = 10;
Цена = 150.5;
Сумма = Количество * Цена; // 1505
Составных операторов вроде +=, ++ или -- в языке 1С нет. Счётчик увеличивают явно: Сч = Сч + 1;.
Тот же знак = внутри условия означает сравнение. Платформа различает это по месту: в начале оператора — присваивание, внутри выражения — проверка на равенство. Двойного == в языке нет.
Арифметические операции
| Операция | Знак | Пример | Результат |
|---|---|---|---|
| Сложение | + | 7 + 3 | 10 |
| Вычитание | - | 7 - 3 | 4 |
| Умножение | * | 7 * 3 | 21 |
| Деление | / | 7 / 2 | 3.5 |
| Остаток от деления | % | 7 % 3 | 1 |
| Унарный минус | - | -7 | -7 |
Деление в 1С всегда даёт точный результат с дробной частью. Целую часть берут функцией Цел(): Цел(7 / 2) вернёт 3.
Знак + работает и со строками, и с датами:
- 🔤
"Счёт № " + "125"→"Счёт № 125"— конкатенация; - 📅
Дата + 86400— дата на сутки позже, к дате прибавляются секунды; - ⏱
ДатаКонца - ДатаНачала— разница в секундах; чтобы получить дни, разделите на 86400.
Тип результата определяет левый операнд. "1" + 1 даст строку "11", а 1 + "1" — число 2: платформа попытается привести строку к числу. Если строка не число, выполнение упадёт с ошибкой преобразования. Явно приводите типы: Строка(), Число(), Формат().
Операции сравнения
=, <>, <, >, <=, >=. Результат — Истина или Ложь. «Не равно» пишется только как <>, вариант != вызовет синтаксическую ошибку.
На равенство можно сравнивать значения любых типов. А вот «больше/меньше» допустимы только для значений одного примитивного типа: числа с числом, строки со строкой, даты с датой, булево с булевым.
Тернарная операция ?()
Краткая запись условия внутри выражения:
Статус = ?(Остаток > 0, "Есть на складе", "Нет в наличии");
Из двух выражений вычисляется только то, которое выбрано условием. Поэтому так можно безопасно защититься от деления на ноль: ?(Кол = 0, 0, Сумма / Кол).
Логические операции и управление ходом программы
И, ИЛИ, НЕ
| Операция | Английский вариант | Истина, когда… |
|---|---|---|
И | AND | истинны оба операнда |
ИЛИ | OR | истинен хотя бы один |
НЕ | NOT | операнд ложен |
Логические выражения в 1С вычисляются по сокращённой схеме: как только результат ясен, остальное не считается. В Ссылка <> Неопределено И Ссылка.ПометкаУдаления второе условие не выполнится, если первое ложно. На этом держится защита от обращения к свойству пустого значения.
Условный оператор Если
Если Сумма > 100000 Тогда
Скидка = 0.1;
ИначеЕсли Сумма > 50000 Тогда
Скидка = 0.05;
Иначе
Скидка = 0;
КонецЕсли;
Ветвей ИначеЕсли может быть сколько угодно. Отдельного оператора выбора вроде switch или case в языке нет — его заменяет цепочка ИначеЕсли.
Три вида циклов
- 🔁
Для Сч = 1 По 10 Цикл … КонецЦикла;— счётчик идёт с шагом 1. Шаг задать нельзя; для обратного обхода используют отдельную формулу индекса. - 📦
Для Каждого Строка Из ТаблицаТоваров Цикл … КонецЦикла;— перебор коллекции: таблицы значений, массива, структуры, выборки. - ⏳
Пока Условие Цикл … КонецЦикла;— повторяет тело, пока условие истинно.
Внутри любого цикла работают два оператора:
Прервать;— немедленно выйти из цикла;Продолжить;— пропустить остаток тела и перейти к следующей итерации.
Для Каждого Строка Из Товары Цикл
Если Строка.Количество = 0 Тогда
Продолжить; // пустые строки пропускаем
КонецЕсли;
Если Строка.Номенклатура.Пустая() Тогда
Прервать; // дальше разбирать нечего
КонецЕсли;
Итог = Итог + Строка.Сумма;
КонецЦикла;
Удалять элементы коллекции внутри Для Каждого нельзя — перебор собьётся. Удаляют обратным циклом по индексу:
Всего = Товары.Количество();
Для Сч = 1 По Всего Цикл
Индекс = Всего - Сч;
Если Товары[Индекс].Количество = 0 Тогда
Товары.Удалить(Индекс);
КонецЕсли;
КонецЦикла;
Возврат и Перейти
Возврат завершает процедуру или функцию. В функции после него пишут значение: Возврат Сумма;. Если функция дошла до КонецФункции без Возврат, она вернёт Неопределено.
Перейти ~Метка; передаёт управление на строку с меткой ~Метка:. Оператор в языке есть, но в живом коде почти не встречается: логика с переходами плохо читается. Обходитесь циклами и Прервать.
Попытка, ВызватьИсключение и прерывание выполнения
Конструкция Попытка … Исключение
Попытка
Результат = Сумма / Количество;
Исключение
Результат = 0;
ЗаписьЖурналаРегистрации("Расчёт",
УровеньЖурналаРегистрации.Ошибка,,,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
Если в блоке Попытка возникла ошибка, выполнение сразу переходит в блок Исключение. Ошибки нет — блок Исключение пропускается.
Внутри обработчика доступны:
ИнформацияОбОшибке()— объект с описанием, модулем и номером строки;ПодробноеПредставлениеОшибки(...)— полный текст со стеком, для журнала;КраткоеПредставлениеОшибки(...)— короткий текст, для пользователя;ОписаниеОшибки()— строка с текстом ошибки, старый, но рабочий способ.
ВызватьИсключение
Оператор останавливает выполнение и передаёт ошибку вверх по стеку вызовов:
Если НЕ ЗначениеЗаполнено(Контрагент) Тогда
ВызватьИсключение "Не указан контрагент";
КонецЕсли;
Внутри блока Исключение можно написать просто ВызватьИсключение; без текста. Тогда наверх уйдёт исходная ошибка со всеми подробностями. Это нужно, когда вы хотите что-то прибрать, но не скрывать сбой.
Попытка и транзакции
Самый частый и самый важный сценарий — запись данных в транзакции:
НачатьТранзакцию();
Попытка
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
Если ошибку внутри транзакции перехватить и не вызвать ОтменитьТранзакцию(), транзакция останется открытой, а следующие записи в этом сеансе завершатся ошибкой. Поэтому в обработчике всегда сначала отмена, потом повторный вызов исключения.
Сводная таблица: виды операторов и приоритет операций
Виды операторов языка 1С
| Группа | Операторы | Зачем |
|---|---|---|
| Присваивание | = | записать значение в переменную или свойство |
| Ветвление | Если … Тогда … ИначеЕсли … Иначе … КонецЕсли, ?() | выбрать действие по условию |
| Циклы | Для … По, Для Каждого … Из, Пока | повторить действие |
| Управление циклом | Прервать, Продолжить | выйти или перейти к следующему шагу |
| Выход и переход | Возврат, Перейти | завершить метод, прыгнуть на метку |
| Исключения | Попытка … Исключение … КонецПопытки, ВызватьИсключение | обработать или поднять ошибку |
| Создание объекта | Новый | создать массив, структуру, запрос и т.д. |
| Динамический код | Выполнить, Вычислить() | исполнить строку как код |
| Асинхронность | Асинх, Ждать | дождаться результата без блокировки клиента |
Ждать и модификатор Асинх появились в платформе 8.3.18; в более ранних версиях асинхронный код пишут через ОписаниеОповещения.
Приоритет операций — от высшего к низшему
| Уровень | Операции |
|---|---|
| 1 | скобки ( ) |
| 2 | унарные + и - |
| 3 | *, /, % |
| 4 | бинарные +, - |
| 5 | сравнение =, <>, <, >, <=, >= |
| 6 | НЕ |
| 7 | И |
| 8 | ИЛИ |
Операции одного уровня выполняются слева направо. Проверим на примере:
2 + 3 * 4→ сначала3 * 4 = 12, потом2 + 12 = 14;(2 + 3) * 4→5 * 4 = 20;А ИЛИ Б И В→ читается какА ИЛИ (Б И В), потому чтоИсильнееИЛИ.
Таблицу приоритетов полезно знать, чтобы читать чужой код. В своём коде ставьте скобки в любом смешанном условии с И/ИЛИ — следующий разработчик скажет спасибо.
Новый, Выполнить и Вычислить: операторы для особых случаев
Новый создаёт объект встроенного типа. Две формы записи равнозначны:
Массив = Новый Массив;
Структура = Новый("Структура"); // имя типа строкой
Запрос = Новый Запрос("ВЫБРАТЬ 1");
Вторая форма нужна, когда имя типа становится известно только во время работы.
Вычислить(Выражение) считает строку как выражение и возвращает значение. Выполнить(Код) исполняет строку как набор операторов и ничего не возвращает.
Никогда не передавайте в Выполнить и Вычислить текст, который ввёл пользователь или пришёл извне. Это дыра: через строку можно выполнить любой код с правами сеанса. Кроме того, динамический код не проверяется при компиляции, и ошибки в нём всплывают только во время работы.
Директивы &НаСервере, &НаКлиенте и инструкции препроцессора #Если Сервер Тогда … #КонецЕсли, #Область к операторам не относятся. Они управляют компиляцией и выглядят похоже, но выполняются до запуска кода.
Ошибки с операторами 1С и как писать код быстрее
Ошибки, которые встречаются чаще всего
- ❌
!=и==вместо<>и=. Привычка из других языков. Модуль не скомпилируется:Синтаксическая ошибка. - ❌ Сравнение
НЕ А = Б, когда хотелиА <> Б. Работает верно благодаря приоритету, но читается двусмысленно. ПишитеА <> БилиНЕ (А = Б). - ❌ Пустой блок
Исключение. Ошибка исчезает бесследно, данные записываются наполовину, а причину не найти. Минимум — запись в журнал регистрации. - ❌ Деление без проверки делителя. Даёт исключение
Деление на 0. Защищайтесь через?()илиЕсли. - ❌ Сравнение даты с пустой датой через
<. Пустая дата —'00010101', она меньше любой реальной. Для проверки заполненности используйтеЗначениеЗаполнено(). - ❌ Изменение коллекции внутри
Для Каждого. Удаляйте обратным циклом по индексу, как показано выше. - ❌ Склейка числа со строкой без формата.
"Сумма: " + 1500000даст"Сумма: 1 500 000"с неразрывными пробелами. Для выгрузок пишитеФормат(Сумма, "ЧГ=0").
Как сделать код быстрее
- Не выполняйте запрос в цикле. Сто итераций — сто обращений к базе. Соберите параметры в массив и получите данные одним запросом с
В (&Список). - Не обращайтесь через точку к реквизитам ссылки в цикле.
Строка.Номенклатура.Артикулкаждый раз читает объект из базы. Получите нужные поля сразу в запросе. - Выходите из цикла раньше. Нашли нужный элемент —
Прервать. Для поиска по таблице значений есть методыНайти()иНайтиСтроки(), они быстрее ручного перебора. - Ставьте дешёвое условие первым. Благодаря сокращённому вычислению
ЭтоНовый И ПроверитьОстатки()не запустит тяжёлую функцию, если документ не новый. - Не оборачивайте в
Попыткакаждую строку цикла. Обработайте ошибку один раз снаружи, если поведение при сбое одинаковое. - Обходитесь без
Выполнить. Динамический код медленнее и опаснее. Чаще всего его заменяетСтруктураили соответствие с готовыми значениями.
Частые вопросы
Есть ли в языке 1С оператор switch или case?
Если … ИначеЕсли … Иначе … КонецЕсли. Для сопоставления «значение → результат» удобно использовать Соответствие.Можно ли задать шаг в цикле Для?
Пока с ручным изменением счётчика или пересчитывайте индекс внутри тела.Чем Прервать отличается от Возврат?
Прервать выходит только из текущего цикла, и выполнение продолжается после КонецЦикла. Возврат завершает всю процедуру или функцию целиком.Почему ошибка внутри Попытки всё равно показывается пользователю?
Исключение стоит ВызватьИсключение — он передаёт ошибку выше. Либо сбой произошёл вне блока Попытка — до него или после КонецПопытки.Нужно ли ставить точку с запятой после КонецЕсли и КонецЦикла?
;. Исключение — когда за ними сразу идёт другое завершающее слово, например КонецПроцедуры.