I. Базовые ветвления if / if-else
- Выражение в скобках
ifобязательно должно быть логическим; неявное преобразование к логическому типу запрещено. - Можно последовательно записывать несколько блоков
else if, в конце опционально добавитьelse. - При одной строке кода фигурные скобки можно опустить, но рекомендуется использовать их всегда для улучшения читаемости.
void main() {
bool isRaining = false;
bool isSnowing = true;
if (isRaining) {
print("Взять плащ от дождя");
} else if (isSnowing) {
print("Надеть толстую куртку");
} else {
print("Ехать на кабриолете");
}
}Code language: Dart (dart)
Результат выполнения
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Надеть толстую курткуCode language: CSS (css)
Также можно использовать только if без остальных веток
void main() {
bool isRaining = false;
bool isSnowing = true;
if (isRaining) {
print("Взять плащ от дождя");
}
}Code language: Dart (dart)
Или просто конструкцию if else
void main() {
bool isRaining = false;
bool isSnowing = true;
if (isRaining) {
print("Взять плащ от дождя");
} else {
print("Ехать на кабриолете");
}
}Code language: Dart (dart)
II. Ветвление по шаблону if-case (Dart 3.0+)
- Если шаблон совпадает, переменные деструктуризируются и привязываются к текущей области видимости.
- При несовпадении управление переходит в else. Можно добавить охранник
whenдля дополнительных логических проверок. - Предназначено для сопоставления одного значения с одним шаблоном; для множества шаблонов используйте switch.
void main() {
final pair = [100, 220];
// Совпадает со списком из двух целых чисел
if (pair case [int x, int y]) {
print("Координаты: $x,$y");
} else {
throw FormatException("Некорректные координаты");
}
}Code language: Dart (dart)
Результат выполнения
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Координаты: 10,20Code language: CSS (css)
2: if-case с охранником when
void main() {
final data = [8, 9];
if (data case [int a, int b] when a > 5 && b > 5) {
print("Оба числа больше 5");
} else {
print("Числа не удовлетворяют условию");
}
}Code language: Dart (dart)
Результат выполнения
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Оба числа больше 5Code language: CSS (css)
III. Оператор switch
Традиционный switch как оператор, не возвращающий значение
- В case допустимы любые шаблоны: строки, константы, логическое ИЛИ, реляционные шаблоны
- Непустые case автоматически завершаются break, ручной break не нужен; пустые case вызывают неявное проваливание (fallthrough).
- Два способа принудительного проваливания:
continue метка/ последовательные пустые case - Если ни один case не подошёл, выполняется
default; поддерживается работа с охранникамиwhen
1: Простое сопоставление строк
void main() {
String command = "OPEN";
switch (command) {
case "CLOSED":
print("Выполнить логику закрытия");
case "PENDING":
print("Выполнить логику ожидания");
case "OPEN":
print("Выполнить логику открытия");
default:
print("Неизвестная команда");
}
}
Code language: Dart (dart)
Результат выполнения
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Выполнить логику открытияCode language: CSS (css)
2: Проваливание через пустой case + переход по continue с меткой
String command = "OPEN";
switch (command) {
case "OPEN":
print("Операция открытия"); // ① Совпадает с OPEN, вывод текста
continue newCase; // ② Прямой переход на метку newCase, возврата нет
case "DENIED":
case "CLOSED":
print("Операция закрытия");
newCase: // ③ Цель перехода
case "PENDING":
print("Общая логика для ожидающих процессов"); // ④ Проверка command == "PENDING" пропускается, код выполняется сразу
}Code language: Dart (dart)
Результат выполнения
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Операция открытия
Общая логика для ожидающих процессовCode language: CSS (css)
В этом примере
continue newCase;переходит на метку newCase, но следующий case «PENDING» не подходит — почему всё равно запускаетсяprint("Общая логика для ожидающих процессов");?Этот вопрос задают многие читатели
continue метка; не повторно проверяет сравниваемое значение, а прямо переходит к началу помеченного case-блока, пропускает все проверки условий и немедленно исполняет код внутри блока.
3: switch с охранником when
void main() {
int score = 88;
switch (score) {
case int s when s >= 90:
print("Отлично");
case int s when s >= 60:
print("Зачёт");
default:
print("Незачёт");
}
}
Code language: Dart (dart)
Вывод: Зачёт
Сначала проверяется тип: значение должно быть целым числом. При совпадении значение записывается в переменную s, затем охранник when выполняет вторую проверку; код case работает только при соблюдении условия when. Две записи int s имеют независимые области видимости и не мешают друг другу.
Каждая конструкция case int s — это независимая привязка шаблона, область видимости переменной ограничена только своим case-блоком.
Можно использовать разные имена переменных в двух case, поведение программы не изменится.
switch (score) {
case int a when a >= 90:
print("Отлично");
case int b when b >= 60:
print("Зачёт");
default:
print("Незачёт");
}Code language: Dart (dart)
IV. Выражение switch
Синтаксис доступен с Dart 3.0, возвращает значение, часто используется для присваивания переменным
Отличия от оператора switch
- Отсутствует ключевое слово
case, символ=>разделяет шаблон и возвращаемое выражение - Каждая ветка обязана возвращать выражение, ветви разделяются запятыми
- Нет неявного проваливания, все ветви независимы. При отсутствии совпадений используйте подчёркивание
_вместо default - Допустимо прямое использование в присваиваниях, вызовах print, return и любых контекстах выражений
1: Простое сопоставление символьных операторов (шаблон логического ИЛИ)
void main() {
const slash = 47, star = 42, comma = 44;
int charCode = 42;
final token = switch (charCode) {
slash || star => "Оператор",
comma => "Знак препинания",
_ => "Недопустимый символ"
};
print(token);
}
Code language: Dart (dart)
Результат выполнения
Оператор
В примере заданы константы с ASCII-кодами трёх символов, переменная charCode классифицирует символ как оператор, знак препинания или недопустимый знак.
2: Выражение switch с охранником when
void main() {
int age = 22;
String level = switch (age) {
int a when a < 18 => "Несовершеннолетний",
int a when a < 30 => "Молодой взрослый",
_ => "Взрослый"
};
print(level);
}Code language: Dart (dart)
Результат выполнения
Молодой взрослый
3: Прямое использование выражения switch в return функции
void main() {
print(getDesc(3));
}
String getDesc(int num) => switch (num) {
1 => "Один",
2 => "Два",
_ => "Другое число"
};
Code language: Dart (dart)
Результат выполнения
Другое число
Примечание: здесь switch является выражением, getDesc — стрелочная функция. Стрелочные функции — уникальный синтаксис Dart, отсутствующий в других языках семейства C.
V. Проверка полноты покрытия (Exhaustiveness Checking)
При отсутствии case для возможных входных значений возникает ошибка компиляции, компилятор требует добавить недостающие ветви. Запечатанные классы sealed и перечисления enum поддерживают полную проверку из коробки без использования _ или default.
1: Ошибка неполного покрытия для nullable логического типа (закомментируйте/раскомментируйте для просмотра ошибки)
void main() {
bool? nullableBool = null;
// Раскомментирование кода ниже вызовет ошибку компиляции: нет case для null и отсутствует запасной вариант _/default
/*
switch (nullableBool) {
case true:
print("Истина");
case false:
print("Ложь");
}
*/
// Исправление: добавить case null или запасной вариант через _
switch (nullableBool) {
case true:
print("Истина");
case false:
print("Ложь");
case null:
print("Значение null");
}
}Code language: PHP (php)
Результат выполнения
Значение nullCode language: JavaScript (javascript)
2: Запечатанный класс sealed
Алгебраический тип данных, принудительно требующий полного сопоставления шаблонов
import 'dart:math' as math;
// sealed-класс: подклассы можно определять только в текущем файле
sealed class Shape {}
// Подкласс Квадрат: длина стороны
class Square implements Shape {
final double length;
Square(this.length);
}
//Подкласс Круг: радиус
class Circle implements Shape {
final double radius;
Circle(this.radius);
}
// Стрелочная функция, вычисляющая площадь через сопоставление switch по полученному объекту подкласса
double calculateArea(Shape shape) => switch (shape) {
Square(length: var l) => l * l,
Circle(radius: var r) => math.pi * r * r
// Добавление нового подкласса Shape вызовет ошибку компиляции из-за отсутствия соответствующего case
};
void main() {
final Shape circle = Circle(5);
print(calculateArea(circle));
final Shape square = Square(4);
print(calculateArea(square));
}
Code language: Dart (dart)
Результат выполнения
78.53981633974483
16.0Code language: CSS (css)
3: Полное сопоставление с enum
Запасное подчёркивание _ не требуется
void main() {
final Animal animal = Animal.cat;
String name = switch (animal) {
Animal.dog => "Собака",
Animal.cat => "Кот"
};
print(name);
}
enum Animal { dog, cat }
Code language: Dart (dart)
Вывод: Кот
Перечисления enum имеют фиксированный конечный набор значений, поэтому запасная ветвь не нужна.
VI. Охранники when
Полностью поддерживаются в if-case, операторах switch и выражениях switch
Роль when: дополнительная логическая проверка после успешного сопоставления шаблона. Если охранник возвращает false, переход на следующую ветвь без выхода из switch.
1. if-case + when
void main() {
List<int> arr = [10, 20];
if (arr case [int x, int y] when x + y > 20) {
print("Сумма двух чисел больше 20");
}
}Code language: Dart (dart)
Сумма двух чисел больше 20
Сначала проверяется, является ли переменная списком из двух целых чисел, при совпадении when проверяет, превышает ли их сумма 20.
2. Оператор switch + when
void main() {
int num = 15;
switch(num) {
case int n when n % 2 == 0:
print("Чётное число");
case int n when n % 2 != 0:
print("Нечётное число");
}
}
Code language: PHP (php)
Вывод: Нечётное число
Сначала подтверждается целочисленный тип, затем проверяется условие внутри when.
3. Выражение switch + when
void main() {
int num = 15;
String res = switch(num) {
int n when n % 2 == 0 => "Чётное число",
_ => "Нечётное число"
};
print(res);
}
Code language: PHP (php)