Что умеет каждый оператор встроенного языка 1С:Предприятия 8.3

· 10 мин

Содержание

Операторы в языке 1С делятся на две группы. Первая — знаки операций внутри выражений: + - * / %, сравнения = <> < > <= >= и логические И, ИЛИ, НЕ. Вторая — управляющие конструкции: Если, Для, Пока, Попытка, Возврат, Прервать, Продолжить и другие. Функции и примеры использования каждого — ниже, с кодом, который можно вставить в обработку и проверить.

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

Арифметические, логические операторы и операции сравнения в 1С

Арифметика

ОператорЧто делаетПримерРезультат
+сложение, склейка строк, сдвиг даты10 + 515
-вычитание, разница дат10 - 55
*умножение4 * 2.510
/деление7 / 23.5
%остаток от деления7 % 21
унарный -смена знака-Сумма—

Деление в 1С всегда дробное: 7 / 2 даёт 3.5, а не 3. Целую часть берут функцией Цел(7 / 2), округление — Окр(Число, 2).

Оператор + ведёт себя по-разному в зависимости от типа левого операнда:

  • 🔢 5 + "3" → 8: строка приводится к числу;
  • 🔤 "5" + 3 → "53": число приводится к строке;
  • 📅 Дата + 86400 → та же дата через сутки: к дате прибавляются секунды;
  • ⏱ Дата2 - Дата1 → число секунд между датами.
ДатаНачала = '20260101';
ДатаКонца  = '20260115';
Дней = (ДатаКонца - ДатаНачала) / 86400; // 14
СрокОплаты = ТекущаяДатаСеанса() + 10 * 86400; // через 10 дней

При склейке строки с числом платформа форматирует число с разделителем групп: "Сумма: " + 1500 выдаст Сумма: 1 500 с неразрывным пробелом. Для имён файлов, кодов и обменов используйте Формат(Сумма, "ЧГ=0") или СтрШаблон("Сумма: %1", Формат(Сумма, "ЧГ=0")).

Сравнение

= — равно, <> — не равно, <, >, <=, >= — больше и меньше. Результат всегда Истина или Ложь.

Значения разных типов на равенство сравнивать можно: 1 = "1" вернёт Ложь, ошибки не будет. А вот < и > между числом и строкой вызовут ошибку выполнения. Ссылки на объекты сравнивают только на = и <>.

Логические операторы

  • ✅ И — истина, если истинны оба операнда;
  • 🔀 ИЛИ — истина, если истинен хотя бы один;
  • 🚫 НЕ — отрицание.

Логические выражения в 1С вычисляются по сокращённой схеме. Если левая часть И ложна, правая не вычисляется. На этом построена привычная защита от ошибки:

Если ЗначениеЗаполнено(Договор) И Договор.ВидДоговора = Перечисления.ВидыДоговоровКонтрагентов.СПоставщиком Тогда
    // обращения к реквизиту пустой ссылки не будет
КонецЕсли;

Если поменять условия местами, при пустом договоре код всё равно отработает, но лишний раз прочитает данные. На объектах вроде Неопределено перестановка ведёт уже к ошибке «Поле объекта не обнаружено».

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

Платформа выполняет операции по старшинству, а внутри одного уровня — слева направо.

УровеньОперации
1 (выше всех)скобки ( )
2унарный минус
3*, /, %
4+, -
5сравнения =, <>, <, >, <=, >=
6НЕ
7И
8 (ниже всех)ИЛИ

Пример, на котором ошибаются чаще всего:

// Хотели: (оптовый ИЛИ VIP) И сумма больше 10 000
Если ЭтоОпт ИЛИ ЭтоVIP И Сумма > 10000 Тогда

Здесь И сильнее ИЛИ, поэтому условие читается как ЭтоОпт ИЛИ (ЭтоVIP И Сумма > 10000). Оптовый клиент получит скидку даже на заказ в 500 рублей.

Ставьте скобки всегда, когда в одном условии смешаны И и ИЛИ. Код станет длиннее на два символа, а читать его будет проще любому, кто откроет модуль после вас.

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

Знак = в 1С означает и присваивание, и сравнение. Смысл определяет место: в начале оператора — присваивание, внутри выражения — сравнение.

Итого = Цена * Количество;          // присваивание
Флаг  = (Итого = 0);                // справа сравнение, результат Булево

Объявление переменных

  • 📌 Внутри процедуры переменная появляется при первом присваивании, объявлять её не обязательно.
  • 📌 Перем Имя; объявляет переменную явно. До присваивания её значение — Неопределено.
  • 📌 Переменные модуля объявляют Перем в начале модуля. С ключевым словом Экспорт переменная модуля объекта или формы доступна снаружи.
Перем КэшНастроек Экспорт; // в модуле объекта

Процедура ПересчитатьСумму()
    Перем Результат;
    Результат = 0;
    Для Каждого Строка Из Товары Цикл
        Результат = Результат + Строка.Сумма;
    КонецЦикла;
    СуммаДокумента = Результат;
КонецПроцедуры

Другие операторы, связанные со значениями

  • 🆕 Новый — создаёт объект: Новый ТаблицаЗначений, Новый Структура("Код, Имя"), Новый Массив.
  • ↩️ Возврат — выход из процедуры или возврат значения из функции: Возврат Итого;.
  • 🏷 Перейти ~Метка; — безусловный переход. В языке он есть, но в рабочем коде почти не нужен: его заменяют Прервать, Продолжить и Возврат.

Константы-литералы: строки в двойных кавычках ("Текст", кавычка внутри удваивается: "Ответ ""ок"""), даты в одинарных ('20261007'), булево — Истина и Ложь, пустые значения — Неопределено и Null.

Условные операторы 1С: Если и ?()

Полная конструкция

Если Остаток < 0 Тогда
    Сообщить("Отрицательный остаток");
ИначеЕсли Остаток = 0 Тогда
    Сообщить("Товар закончился");
Иначе
    Сообщить("В наличии: " + Формат(Остаток, "ЧГ=0"));
КонецЕсли;
  • Веток ИначеЕсли может быть сколько угодно, ветка Иначе необязательна.
  • Платформа проверяет условия сверху вниз и выполняет первую подходящую ветку. Остальные пропускает.
  • После КонецЕсли ставится точка с запятой.

Аналога switch/case нет. Цепочка ИначеЕсли и есть способ выбрать один вариант из многих. Если вариантов десятки, удобнее заполнить Соответствие и брать значение по ключу.

Тернарный оператор

Короткая форма для выражений: ?(Условие, ЕслиИстина, ЕслиЛожь).

Ставка = ?(ЭтоНерезидент, 30, 13);
Представление = ?(ПустаяСтрока(Комментарий), "без комментария", Комментарий);

Тернарный оператор возвращает значение, его нельзя использовать как отдельный оператор. Вложенные ?(…, ?(…)) формально допустимы, но после второго уровня их проще переписать на Если.

Лишние сравнения с Истиной

Если Проведен = Истина Тогда работает, но избыточно. Пишут Если Проведен Тогда и Если НЕ Проведен Тогда.

Операторы циклов в 1С и управление итерациями

В языке три вида циклов.

ЦиклКогда применятьСинтаксис
Для … Поизвестно число повторовДля Сч = 1 По 10 Цикл … КонецЦикла;
Для Каждого … Изобход коллекцииДля Каждого Стр Из Товары Цикл … КонецЦикла;
Покаповторять, пока верно условиеПока Выборка.Следующий() Цикл … КонецЦикла;

Цикл со счётчиком

Шаг у Для … По всегда равен 1, ключевого слова для шага нет. Нужен шаг 2 или обратный порядок — используйте Пока или пересчитывайте индекс.

Обход коллекции

Для Каждого обходит массивы, таблицы и деревья значений, табличные части, структуры и соответствия. Выборку из результата запроса так не обойти: для неё нужен Пока Выборка.Следующий() Цикл.

Прервать и Продолжить

  • ⛔ Прервать — немедленный выход из цикла.
  • ⏭ Продолжить — переход к следующей итерации.
Для Каждого Строка Из Товары Цикл
    Если Строка.Количество = 0 Тогда
        Продолжить; // пустые строки пропускаем
    КонецЕсли;
    Если Строка.Номенклатура = НайденнаяПозиция Тогда
        НомерСтроки = Строка.НомерСтроки;
        Прервать;   // нашли — дальше искать незачем
    КонецЕсли;
КонецЦикла;

Удаление элементов в цикле

Удалять строки внутри Для Каждого нельзя: после удаления сдвигаются индексы и часть строк пропускается. Обходите коллекцию с конца:

Всего = Товары.Количество();
Для Сч = 1 По Всего Цикл
    Строка = Товары[Всего - Сч];
    Если Строка.Количество = 0 Тогда
        Товары.Удалить(Строка);
    КонецЕсли;
КонецЦикла;

Граница Всего посчитана до цикла, поэтому удаление на неё не влияет. Индексы идут от Всего - 1 до 0, то есть строки обходятся от последней к первой.

Цикл Пока без изменения условия внутри тела — бесконечный. В тонком клиенте это выглядит как зависшая форма. Прервать выполнение можно сочетанием Ctrl+Break, но несохранённые данные формы при этом могут потеряться.

Обработка исключений: Попытка, Исключение, ВызватьИсключение

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

Попытка
    Файл = Новый ЧтениеТекста(ПутьКФайлу, КодировкаТекста.UTF8);
    Текст = Файл.Прочитать();
    Файл.Закрыть();
Исключение
    Инфо = ИнформацияОбОшибке();
    ЗаписьЖурналаРегистрации("Загрузка прайса",
        УровеньЖурналаРегистрации.Ошибка, , ,
        ПодробноеПредставлениеОшибки(Инфо));
    Сообщить("Не удалось прочитать файл: " + КраткоеПредставлениеОшибки(Инфо));
КонецПопытки;

Что здесь происходит:

  1. Код между Попытка и Исключение выполняется как обычно.
  2. При первой же ошибке управление переходит в блок Исключение, остаток блока Попытка пропускается.
  3. ИнформацияОбОшибке() возвращает объект с описанием ошибки, модулем и номером строки.
  4. ПодробноеПредставлениеОшибки() даёт полный текст со стеком — его пишут в журнал регистрации. КраткоеПредставлениеОшибки() — короткий текст для пользователя.

Свои ошибки и повторный выброс

  • ВызватьИсключение "Не заполнен склад"; — прерывает выполнение с вашим текстом. Если выше по стеку нет Попытки, пользователь увидит окно с этим сообщением.
  • ВызватьИсключение; без параметров допустим только внутри блока Исключение. Он пробрасывает исходную ошибку дальше, сохраняя её текст.

Пустой блок Исключение … КонецПопытки — худшее, что можно сделать с ошибкой. Сбой исчезает без следа, а через месяц бухгалтер находит недопроведённые документы и никто не понимает почему. Минимум — запись в журнал регистрации.

Не оборачивайте в Попытку то, что можно проверить заранее. Вместо ловли деления на ноль проверьте делитель: Если Количество <> 0 Тогда. Попытка нужна для внешних операций: файлы, COM, HTTP, запись объектов.

Операторы работы с транзакциями и блокировками

Строго говоря, транзакции в 1С управляются не операторами, а методами глобального контекста. Но пишутся они рядом с Попыткой и в коде воспринимаются как одна конструкция.

МетодНазначение
НачатьТранзакцию()открывает транзакцию
ЗафиксироватьТранзакцию()записывает все изменения разом
ОтменитьТранзакцию()откатывает все изменения
ТранзакцияАктивна()возвращает Истина, если транзакция открыта

Шаблон, принятый в типовых конфигурациях:

НачатьТранзакцию();
Попытка
    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах");
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    ЭлементБлокировки.УстановитьЗначение("Склад", Склад);
    Блокировка.Заблокировать();

    // чтение остатков и запись документов
    ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);

    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ЗаписьЖурналаРегистрации("Перемещение товаров",
        УровеньЖурналаРегистрации.Ошибка, , ,
        ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
    ВызватьИсключение;
КонецПопытки;

Правила, которые стоит держать в голове:

  • 🔒 НачатьТранзакцию() ставится до Попытки. Если транзакция не открылась, откатывать нечего.
  • 🔁 Вложенных транзакций в полном смысле нет. Внутренний НачатьТранзакцию() лишь увеличивает счётчик, а ОтменитьТранзакцию() на любом уровне откатывает всё.
  • 🧱 После ошибки внутри транзакции её уже нельзя продолжать. Попытка записать что-то ещё даст ошибку «В данной транзакции уже происходили ошибки». Поэтому Попытка внутри транзакции, которая «гасит» ошибку и идёт дальше, не спасает.
  • 📦 Записать() у объекта сам открывает транзакцию, если её нет. Явная транзакция нужна, когда несколько записей должны пройти вместе или не пройти вовсе.
  • 🔐 Управляемая блокировка БлокировкаДанных действует только внутри транзакции и снимается при её завершении.

Не держите транзакцию открытой во время диалога с пользователем или долгого HTTP-запроса. Пока она активна, заблокированные данные недоступны другим сеансам, и коллеги получат ошибки блокировки при проведении.

Частые ошибки при работе с операторами

  • ❌ Проверка Если Сумма = Неопределено вместо ЗначениеЗаполнено(Сумма). Пустое число — это 0, а не Неопределено, и условие не сработает.
  • ❌ Арифметика с Null. Результат запроса с левым соединением даёт Null в пустых полях, и Null + 100 падает с ошибкой. Обрабатывайте в самом запросе через ЕСТЬNULL(Поле, 0).
  • ❌ Сравнение дробей на точное равенство. После деления Сумма / 3 * 3 может не совпасть с исходной суммой в последнем знаке. Сравнивайте округлённые значения: Окр(А, 2) = Окр(Б, 2).
  • ❌ Изменение переменной цикла внутри Для. Присвоение счётчику внутри тела ломает логику и читается как ошибка. Если нужно управлять шагом — пишите Пока.
  • ❌ Перепутанные Прервать и Возврат. Прервать выходит только из ближайшего цикла, код после КонецЦикла выполнится. Чтобы выйти из процедуры целиком, нужен Возврат.
Проверьте себя
Чему равно выражение "5" + 3?
Что вернёт 7 / 2?
Как читается условие А ИЛИ Б И В?
Где допустим ВызватьИсключение без параметров?

Частые вопросы об операторах 1С

Есть ли в 1С английские названия операторов?
Да. У каждого ключевого слова есть английский вариант: If … Then … ElsIf … Else … EndIf, For Each … In … Do … EndDo, While, Try … Except … EndTry, Raise, AND, OR, NOT. В одном модуле их можно смешивать, но в типовых конфигурациях пишут по-русски.
Чем операторы языка запросов отличаются от встроенного языка?
В запросах свой набор: ВЫБОР КОГДА … ТОГДА … ИНАЧЕ … КОНЕЦ вместо Если, ЕСТЬ NULL, В, ПОДОБНО, МЕЖДУ. Циклов, Если и Попытки в запросах нет.
Можно ли выполнить код, собранный в строку?
Да, оператор Выполнить(Строка) выполняет фрагмент кода, а функция Вычислить(Строка) возвращает значение выражения. Пользуйтесь ими осторожно: ошибка в строке видна только во время выполнения, а код из внешних данных — дыра в безопасности.
Что такое Асинх и Ждать?
Это операторы асинхронного кода, появившиеся в платформе 8.3.18. Ключевое слово Асинх помечает процедуру или функцию, а Ждать приостанавливает её до получения результата, например ответа на вопрос пользователю. Они заменяют цепочки ОписаниеОповещения в клиентском коде.
Нужна ли точка с запятой после каждого оператора?
Да, точка с запятой разделяет операторы. Перед КонецЕсли, КонецЦикла и КонецПопытки её у последнего оператора можно опустить, но лучше ставить всегда, чтобы при добавлении строки не получить синтаксическую ошибку.