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. Приход или расход

Напишите ВидДвижения(Сумма): для отрицательной суммы — расход, иначе приход. Используйте короткую форму ?().

Решается в тренажёре: код запускается и проверяется сразу.

Оператора «выбор» в 1С нет

В других языках для выбора из многих вариантов есть отдельная конструкция — switch, case. В языке 1С её нет: есть только цепочка ИначеЕсли.

Похожее слово ВЫБОР существует, но в другом месте — в языке запросов, и к коду отношения не имеет.

Пока вариантов три-четыре, цепочка читается нормально. Когда их десять и все устроены одинаково — «такому значению соответствует такое», — цепочку заменяют соответствием.

✓ Цепочка на десять веток

Если Категория = "Основной" Тогда
	Ставка = 20;
ИначеЕсли Категория = "Льготный" Тогда
	Ставка = 10;
ИначеЕсли Категория = "Нулевой" Тогда
	Ставка = 0;
// … и так ещё семь раз
КонецЕсли;

Каждый новый вариант — правка кода. Легко ошибиться в одной ветке из десяти и не заметить.

✕ Таблица соответствий

Ставки = Новый Соответствие;
Ставки.Вставить("Основной", 20);
Ставки.Вставить("Льготный", 10);
Ставки.Вставить("Нулевой", 0);

Ставка = Ставки[Категория];
Если Ставка = Неопределено Тогда
	Ставка = 20;   // значение по умолчанию
КонецЕсли;

Варианты — данные, а не код. Добавить новый — одна строка; а в реальной задаче такая таблица чаще всего приезжает из регистра сведений.

Упражнение 5. Ставка по категории

Напишите Ставка(Категория) через соответствие: Основной — 20, Льготный — 10, Нулевой — 0, а для незнакомой категории — 20. Проверка спрашивает про Льготный.

Решается в тренажёре: код запускается и проверяется сразу.

Сравнение значений разных типов

"5" = 5 — это Ложь. Строка и число не равны, как бы похоже они ни выглядели: 1С не приводит их друг к другу при сравнении.

Так же и с остальным: Неопределено = "" — Ложь, NULL = Неопределено — Ложь, Ложь = 0 — Ложь.

Из-за этого условие, сравнивающее реквизит с тем, что пришло из файла или из формы, может молча не срабатывать никогда. Сравнивать надо значения одного типа: преобразовать явно и только потом сравнивать.

Что дальше

Программа научилась выбирать. Следующая глава — циклы: как повторить действие для каждой строки документа, для каждого товара в списке, пока не кончится остаток.

Как закрепить

Читать про код и писать код — разные умения. В тренажёре к этой главе идут упражнения: вы пишете решение, оно запускается на настоящем интерпретаторе 1С и проверяется сразу, без установки платформы.

Открыть эту главу в тренажёре

Даты: границы периода и потерянный последний день
Циклы: повторить для каждого