1C-Code → Основы 1С → Условия: Булево и выбор пути
Четвёртый базовый тип и первое, что делает код умным, — умение выбрать ветку.
Глава 8 из 36 · чтение примерно 24 минут
До сих пор код шёл сверху вниз, выполняя всё подряд. Условие — первое, что даёт ему выбор: сделать одно или другое, в зависимости от данных.
Начнём с типа, на котором условия держатся.
Булево — четвёртый базовый тип 1С, после числа, строки и даты. Значений у него ровно два: Истина и Ложь.
Он бывает не только в условии. Реквизит «Проведён», флажок «Учитывать НДС», результат проверки — всё это Булево, его можно положить в переменную и вернуть из функции.
Разрешено = Истина; // просто значение
Крупный = (Сумма > 100000); // результат сравнения — тоже Булево
Если Крупный Тогда // и его можно проверить
Сообщить("Нужно согласование");
КонецЕсли;
| Часть | Что означает |
|---|---|
Истина / Ложь | два единственных значения типа Булево |
(Сумма > 100000) | сравнение возвращает Булево — его не обязательно проверять сразу |
Если Крупный | переменная уже Булево, сравнивать её ещё раз не с чем |
имя | булеву переменную называют прилагательным: Крупный, Проведён, Найден |
Сравнивать с Истина не нужно
Если Проведён = Истина Тогда — работает, но это лишнее. Проведён уже Истина или Ложь, сравнение ничего не добавляет.
Пишут просто: Если Проведён Тогда, а для отрицания — Если Не Проведён Тогда.
Это не про красоту. Длинная форма провоцирует опечатку Если Проведён = Ложь Тогда там, где имелось в виду «не проведён», и её глазами не поймать.
Конструкция состоит из четырёх слов: Если, Тогда, необязательное Иначе и обязательное КонецЕсли с точкой с запятой.
Если Остаток < 0 Тогда
Сообщить("Отрицательный остаток");
Иначе
Сообщить("Всё в порядке");
КонецЕсли;
| Часть | Что означает |
|---|---|
Если … Тогда | между ними — условие, то есть выражение типа Булево |
отступ | всё, что внутри, сдвигается на одну табуляцию — так видно вложенность |
Иначе | необязательно: часто нужно что-то сделать только при совпадении |
КонецЕсли; | обязательно, и с точкой с запятой — блок закрывается словом, не скобкой |
| Знак | Что означает | Пример |
|---|---|---|
| = | равно | Статус = "Новый" |
| <> | не равно | Статус <> "Закрыт" |
| > | больше | Сумма > 1000 |
| < | меньше | Остаток < 0 |
| >= | больше или равно | Сумма >= 1000 |
| <= | меньше или равно | Дата <= КонецДня(Граница) |
Один знак «равно» на две работы
В 1С = означает и присваивание, и сравнение — в отличие от языков, где для сравнения пишут ==.
Путаницы не возникает: что именно имеется в виду, определяется местом. Сумма = 100; отдельной командой — присваивание. Если Сумма = 100 Тогда — сравнение.
А «не равно» записывается как <>, а не как !=.
Упражнение 1. Крупный заказ
Напишите функцию Крупный(Сумма), возвращающую Истина, если сумма больше 100000. Обойдитесь без Если — сравнение само даёт нужный ответ.
Решается в тренажёре: код запускается и проверяется сразу.
Когда веток больше двух, их соединяют в цепочку словом ИначеЕсли. Пишется слитно.
И вот главное свойство цепочки: проверка идёт сверху вниз и останавливается на первом совпадении. Остальные ветки даже не смотрятся.
| Условие | Результат | Сработает |
|---|---|---|
Сумма ≥ 10000 | скидка 15% | да |
Сумма ≥ 5000 | скидка 10% | нет |
Сумма ≥ 1000 | скидка 5% | нет |
Иначе | скидки нет | нет |
От порядка зависит ответ, а не только скорость
Это не стилистика. Цепочка условий с перекрывающимися границами даёт разный результат при разном порядке веток.
Правило: в цепочке «чем больше, тем лучше» условия идут от строгого к мягкому. Сначала «≥ 10000», потом «≥ 5000», потом «≥ 1000».
Ошибка тихая: скидки будут считаться, документы проводиться, просто крупные клиенты станут получать пять процентов вместо пятнадцати.
Упражнение 2. Скидка по сумме
Напишите функцию Скидка(Сумма): от 10000 — 15, от 5000 — 10, от 1000 — 5, иначе 0. Проверка передаёт 12000 и ждёт 15.
Решается в тренажёре: код запускается и проверяется сразу.
Отдельные Если — это не цепочка
Несколько подряд идущих Если — это несколько независимых проверок. Сработают все подходящие, а не первая.
Если Сумма >= 1000 Тогда Процент = 5; КонецЕсли;
Если Сумма >= 5000 Тогда Процент = 10; КонецЕсли;
// для 7000 выполнятся обе строки, останется 10Здесь ответ верный — но случайно: он держится на том, что строки идут в правильном порядке и последняя затирает предыдущую. Поменяйте их местами, и всё сломается.
Цепочка ИначеЕсли выполняет ровно одну ветку. Она надёжнее и читается однозначно.
И — верны оба. ИЛИ — верно хотя бы одно. Не — переворачивает.
Когда условий много, ставьте скобки. Программа разберётся и без них, но человек, читающий код через год, — не факт.
Если Остаток > 0 И Не Товар.ПометкаУдаления Тогда
Если Статус = "Новый" ИЛИ Статус = "В работе" Тогда
Если (Сумма > 100000 И Не Согласовано) ИЛИ Просрочен Тогда
| Часть | Что означает |
|---|---|
И | оба условия должны быть истинны |
ИЛИ | достаточно одного |
Не | переворачивает: Не Ложь — это Истина |
скобки | без них И считается раньше ИЛИ — и смысл может оказаться не тот |
Проверка обрывается, как только ответ ясен
В условии А И Б вторая часть не вычисляется, если первая оказалась ложной: ответ уже известен. То же с А ИЛИ Б, когда первая часть истинна.
Это не мелочь, а рабочий приём. Сначала ставят проверку существования, потом обращение:
Если ЗначениеЗаполнено(Ссылка) И Ссылка.Проведён Тогда
Если ссылка пустая, до Ссылка.Проведён дело не дойдёт — и обращения к несуществующему не случится. Поменяйте части местами, и защита исчезнет.
Упражнение 3. Можно ли отгружать
Напишите МожноОтгружать(Остаток, Заблокирован): Истина, только если остаток больше нуля и контрагент не заблокирован. Проверка передаёт остаток 5 и блокировку Истина, ожидая Ложь.
Решается в тренажёре: код запускается и проверяется сразу.
Условия внутри условий быстро превращаются в лестницу, у которой не видно ни начала, ни конца. Есть приём, который её распрямляет: сначала отсеять то, что делать не надо, и выйти.
✓ Лестница
Если ЗначениеЗаполнено(Клиент) Тогда
Если Не Клиент.Заблокирован Тогда
Если Сумма > 0 Тогда
// сама работа
КонецЕсли;
КонецЕсли;
КонецЕсли;Полезное действие — на четвёртом уровне вложенности. Через месяц сюда страшно возвращаться.
✕ Ранний выход
Если Не ЗначениеЗаполнено(Клиент) Тогда
Возврат;
КонецЕсли;
Если Клиент.Заблокирован Тогда
Возврат;
КонецЕсли;
Если Сумма <= 0 Тогда
Возврат;
КонецЕсли;
// сама работа — без отступовУсловия читаются как список причин не работать. Главное — слева, а не в глубине.
Когда надо просто выбрать одно из двух значений, есть запись в одну строку: ?(Условие, ЕслиДа, ЕслиНет).
Знак = ?(Сумма < 0, "расход", "приход");
Она удобна ровно до тех пор, пока помещается в строку и не вкладывается сама в себя. Два-три вложенных ?() читаются хуже, чем честная цепочка ИначеЕсли, — и там, где появляется третий вариант, возвращайтесь к Если.
Упражнение 4. Приход или расход
Напишите ВидДвижения(Сумма): для отрицательной суммы — расход, иначе приход. Используйте короткую форму ?().
Решается в тренажёре: код запускается и проверяется сразу.
В других языках для выбора из многих вариантов есть отдельная конструкция — switch, case. В языке 1С её нет: есть только цепочка ИначеЕсли.
Похожее слово ВЫБОР существует, но в другом месте — в языке запросов, и к коду отношения не имеет.
Пока вариантов три-четыре, цепочка читается нормально. Когда их десять и все устроены одинаково — «такому значению соответствует такое», — цепочку заменяют соответствием.
✓ Цепочка на десять веток
Если Категория = "Основной" Тогда
Ставка = 20;
ИначеЕсли Категория = "Льготный" Тогда
Ставка = 10;
ИначеЕсли Категория = "Нулевой" Тогда
Ставка = 0;
// … и так ещё семь раз
КонецЕсли;Каждый новый вариант — правка кода. Легко ошибиться в одной ветке из десяти и не заметить.
✕ Таблица соответствий
Ставки = Новый Соответствие;
Ставки.Вставить("Основной", 20);
Ставки.Вставить("Льготный", 10);
Ставки.Вставить("Нулевой", 0);
Ставка = Ставки[Категория];
Если Ставка = Неопределено Тогда
Ставка = 20; // значение по умолчанию
КонецЕсли;Варианты — данные, а не код. Добавить новый — одна строка; а в реальной задаче такая таблица чаще всего приезжает из регистра сведений.
Упражнение 5. Ставка по категории
Напишите Ставка(Категория) через соответствие: Основной — 20, Льготный — 10, Нулевой — 0, а для незнакомой категории — 20. Проверка спрашивает про Льготный.
Решается в тренажёре: код запускается и проверяется сразу.
Сравнение значений разных типов
"5" = 5 — это Ложь. Строка и число не равны, как бы похоже они ни выглядели: 1С не приводит их друг к другу при сравнении.
Так же и с остальным: Неопределено = "" — Ложь, NULL = Неопределено — Ложь, Ложь = 0 — Ложь.
Из-за этого условие, сравнивающее реквизит с тем, что пришло из файла или из формы, может молча не срабатывать никогда. Сравнивать надо значения одного типа: преобразовать явно и только потом сравнивать.
Программа научилась выбирать. Следующая глава — циклы: как повторить действие для каждой строки документа, для каждого товара в списке, пока не кончится остаток.
Читать про код и писать код — разные умения. В тренажёре к этой главе идут упражнения: вы пишете решение, оно запускается на настоящем интерпретаторе 1С и проверяется сразу, без установки платформы.
← Даты: границы периода и потерянный последний день
→ Циклы: повторить для каждого