Операторы встроенного языка 1С:Предприятие 8.3 — от присваивания до Попытки

· 10 мин

Содержание

Оператор в языке 1С — это одна законченная инструкция модуля: присвоить значение, проверить условие, повторить действие в цикле, перехватить ошибку. Операторы отделяются друг от друга точкой с запятой ;, а внутри них работают операции — +, =, И, ?() и другие.

Путаница начинается, когда новичок читает чужой код: = то присваивает, то сравнивает, НЕ срабатывает не там, где ожидалось, а Попытка молча глотает ошибку. Разберём каждый вид операторов 1С с примерами кода, таблицей приоритетов и типовыми ловушками. Всё сказанное относится к платформе 8.3 и одинаково для любой конфигурации — Бухгалтерии, ЗУП, УТ или своей разработки.

Оператор 1С: определение и правила записи

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

  • 🧩 операторы — то, что выполняется: Если, Для, Пока, Попытка, Возврат, присваивание, вызов процедуры;
  • ➕ операции — то, что вычисляет значение внутри выражения: арифметика, сравнение, логика.

В разговоре оба понятия часто называют «операторами», и это нормально. Главное — понимать разницу: А + Б само по себе ничего не делает, а Сумма = А + Б; уже оператор.

Правила синтаксиса, которые стоит помнить

  1. Каждый оператор заканчивается ;. Перед ключевыми словами КонецЕсли, КонецЦикла, Иначе, Исключение точку с запятой у последнего оператора можно опустить — компилятор не ругается. Но по стандартам разработки её лучше ставить всегда.
  2. Регистр букв не важен: ЕСЛИ, если и Если — одно и то же. То же с именами переменных.
  3. Почти у каждого ключевого слова есть английский вариант: Если — If, Цикл — Do, Попытка — Try. Смешивать языки в одном модуле можно, но читать такой код тяжело.
  4. Один оператор можно растянуть на несколько строк — перенос строки не завершает его. Завершает только ;.
  5. Комментарий начинается с // и идёт до конца строки. Блочных комментариев нет.
// Один оператор на три строки — это корректно
ИтогоКОплате = СуммаДокумента
    + СуммаДоставки
    - СуммаСкидки;

Если строковая константа не помещается в строку, продолжите её с новой строки символом |. Кавычку внутри строки удваивают: "Ошибка ""деления""".

Присваивание и операции в выражениях

Оператор присваивания

Присваивание записывается одним знаком =: слева переменная или свойство, справа выражение.

Количество = 10;
Цена = 150.5;
Сумма = Количество * Цена; // 1505

Составных операторов вроде +=, ++ или -- в языке 1С нет. Счётчик увеличивают явно: Сч = Сч + 1;.

Тот же знак = внутри условия означает сравнение. Платформа различает это по месту: в начале оператора — присваивание, внутри выражения — проверка на равенство. Двойного == в языке нет.

Арифметические операции

ОперацияЗнакПримерРезультат
Сложение+7 + 310
Вычитание-7 - 34
Умножение*7 * 321
Деление/7 / 23.5
Остаток от деления%7 % 31
Унарный минус--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;
  • А ИЛИ Б И В → читается как А ИЛИ (Б И В), потому что И сильнее ИЛИ.

Таблицу приоритетов полезно знать, чтобы читать чужой код. В своём коде ставьте скобки в любом смешанном условии с И/ИЛИ — следующий разработчик скажет спасибо.

Проверьте себя
Чему равно 10 - 4 / 2 в языке 1С?
Как читается условие А ИЛИ Б И В?
Что вернёт выражение "5" + 5?

Новый, Выполнить и Вычислить: операторы для особых случаев

Новый создаёт объект встроенного типа. Две формы записи равнозначны:

Массив = Новый Массив;
Структура = Новый("Структура"); // имя типа строкой
Запрос = Новый Запрос("ВЫБРАТЬ 1");

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

Вычислить(Выражение) считает строку как выражение и возвращает значение. Выполнить(Код) исполняет строку как набор операторов и ничего не возвращает.

Никогда не передавайте в Выполнить и Вычислить текст, который ввёл пользователь или пришёл извне. Это дыра: через строку можно выполнить любой код с правами сеанса. Кроме того, динамический код не проверяется при компиляции, и ошибки в нём всплывают только во время работы.

Директивы &НаСервере, &НаКлиенте и инструкции препроцессора #Если Сервер Тогда … #КонецЕсли, #Область к операторам не относятся. Они управляют компиляцией и выглядят похоже, но выполняются до запуска кода.

Ошибки с операторами 1С и как писать код быстрее

Ошибки, которые встречаются чаще всего

  • ❌ != и == вместо <> и =. Привычка из других языков. Модуль не скомпилируется: Синтаксическая ошибка.
  • ❌ Сравнение НЕ А = Б, когда хотели А <> Б. Работает верно благодаря приоритету, но читается двусмысленно. Пишите А <> Б или НЕ (А = Б).
  • ❌ Пустой блок Исключение. Ошибка исчезает бесследно, данные записываются наполовину, а причину не найти. Минимум — запись в журнал регистрации.
  • ❌ Деление без проверки делителя. Даёт исключение Деление на 0. Защищайтесь через ?() или Если.
  • ❌ Сравнение даты с пустой датой через <. Пустая дата — '00010101', она меньше любой реальной. Для проверки заполненности используйте ЗначениеЗаполнено().
  • ❌ Изменение коллекции внутри Для Каждого. Удаляйте обратным циклом по индексу, как показано выше.
  • ❌ Склейка числа со строкой без формата. "Сумма: " + 1500000 даст "Сумма: 1 500 000" с неразрывными пробелами. Для выгрузок пишите Формат(Сумма, "ЧГ=0").

Как сделать код быстрее

  1. Не выполняйте запрос в цикле. Сто итераций — сто обращений к базе. Соберите параметры в массив и получите данные одним запросом с В (&Список).
  2. Не обращайтесь через точку к реквизитам ссылки в цикле. Строка.Номенклатура.Артикул каждый раз читает объект из базы. Получите нужные поля сразу в запросе.
  3. Выходите из цикла раньше. Нашли нужный элемент — Прервать. Для поиска по таблице значений есть методы Найти() и НайтиСтроки(), они быстрее ручного перебора.
  4. Ставьте дешёвое условие первым. Благодаря сокращённому вычислению ЭтоНовый И ПроверитьОстатки() не запустит тяжёлую функцию, если документ не новый.
  5. Не оборачивайте в Попытка каждую строку цикла. Обработайте ошибку один раз снаружи, если поведение при сбое одинаковое.
  6. Обходитесь без Выполнить. Динамический код медленнее и опаснее. Чаще всего его заменяет Структура или соответствие с готовыми значениями.

Частые вопросы

Есть ли в языке 1С оператор switch или case?
Нет. Выбор из нескольких вариантов пишут цепочкой Если … ИначеЕсли … Иначе … КонецЕсли. Для сопоставления «значение → результат» удобно использовать Соответствие.
Можно ли задать шаг в цикле Для?
Нет, счётчик всегда увеличивается на 1. Для шага 2 или обратного обхода используйте цикл Пока с ручным изменением счётчика или пересчитывайте индекс внутри тела.
Чем Прервать отличается от Возврат?
Прервать выходит только из текущего цикла, и выполнение продолжается после КонецЦикла. Возврат завершает всю процедуру или функцию целиком.
Почему ошибка внутри Попытки всё равно показывается пользователю?
Скорее всего, в блоке Исключение стоит ВызватьИсключение — он передаёт ошибку выше. Либо сбой произошёл вне блока Попытка — до него или после КонецПопытки.
Нужно ли ставить точку с запятой после КонецЕсли и КонецЦикла?
Да, эти слова завершают составной оператор, и после них ставится ;. Исключение — когда за ними сразу идёт другое завершающее слово, например КонецПроцедуры.