Поток управления

Освойте структуры потока управления Топаз. Изучите, как эффективно управлять потоком выполнения программы через условные операторы, циклы, сопоставление образцов и условия-ограждения.

Поток управления определяет порядок выполнения вашей программы. Топаз предоставляет мощные и выразительные структуры потока управления. 🎯

🔀 Условные операторы

Операторы if

let возраст = 25
let оценка = 85

// Базовый оператор if
if возраст >= 18 {
    print("Вы совершеннолетний")
}

// Оператор if-else
if оценка >= 90 {
    print("Оценка A")
} else {
    print("Нужно больше стараться")
}

// Цепочка if-else if
if оценка >= 90 {
    print("Оценка A - Отлично")
} else if оценка >= 80 {
    print("Оценка B - Хорошо")
} else if оценка >= 70 {
    print("Оценка C - Удовлетворительно")
} else {
    print("Требуется пересдача")
}

// Составные условия
let имяПользователя = "ТопазДев"
let попытки = 3

if имяПользователя.length() > 0 && попытки < 5 {
    print("Вы можете попытаться войти в систему")
}

Условные выражения

// Вместо ?: используйте if как выражение (v3)
let статусВзрослости = if возраст >= 18 { "взрослый" } else { "несовершеннолетний" }
let статусСдачи = if оценка >= 60 { "сдал" } else { "не сдал" }

// Вложенные условия
let буквеннаяОценка = if оценка >= 90 { "A" }
    else if оценка >= 80 { "B" }
    else if оценка >= 70 { "C" }
    else { "F" }

// Условное значение
let скидка = if уровеньЧленства == "VIP" { 0.2 }
    else if уровеньЧленства == "Золото" { 0.1 }
    else { 0.05 }

print("Возраст: {возраст}, Статус: {статусВзрослости}")
print("Оценка: {оценка}, Буквенная оценка: {буквеннаяОценка}")

if как выражение

// Использование if как выражения
let сообщение = if время < 12 {
    "Доброе утро!"
} else if время < 18 {
    "Добрый день!"
} else {
    "Добрый вечер!"
}

// Сложное условное вычисление
let стоимостьДоставки = if суммаЗаказа >= 50000 {
    0
} else if расстояние <= 10 {
    3000
} else {
    5000
}

print(сообщение)
print("Стоимость доставки: {стоимостьДоставки} рублей")

🔄 Циклы

Циклы for

// Цикл for с диапазоном
for i in 0..5 {
    print("Итерация {i}")
}

// Включающий диапазон
for i in 1..=10 {
    print("Число: {i}")
}

// Итерация по массиву
let фрукты = ["яблоко", "банан", "апельсин", "виноград"]
for фрукт in фрукты {
    print("Фрукт: {фрукт}")
}

// Итерация с индексом и значением
for (индекс, фрукт) in фрукты.enumerate() {
    print("{индекс}: {фрукт}")
}

// Итерация по ключ-значение объекта
let информацияПользователя = {
    имя: "ТопазДев",
    возраст: 25,
    работа: "разработчик"
}

for (ключ, значение) in информацияПользователя {
    print("{ключ}: {значение}")
}

// Итерация с шагом
for i in (0..20).step(2) {
    print("Четное: {i}")
}

Циклы while

// Базовый цикл while
let mut счетчик = 0
while счетчик < 5 {
    print("Счетчик: {счетчик}")
    счетчик += 1
}

// Условный цикл while
let mut ввод = ""
while ввод != "выход" {
    ввод = input("Введите команду (наберите 'выход' для завершения): ")
    if ввод != "выход" {
        print("Получена команда: {ввод}")
    }
}

// Бесконечный цикл (с break)
let mut попытки = 0
while true {
    попытки += 1
    let успех = Math.random() > 0.8
    
    if успех {
        print("Успех! После {попытки} попыток")
        break
    }
    
    if попытки >= 10 {
        print("Превышено максимальное количество попыток")
        break
    }
}

Управление циклами

// break и continue
for i in 1..=20 {
    if i % 3 == 0 && i % 5 == 0 {
        print("{i}: FizzBuzz")
        continue
    }
    
    if i % 3 == 0 {
        print("{i}: Fizz")
        continue
    }
    
    if i % 5 == 0 {
        print("{i}: Buzz")
        continue
    }
    
    if i > 15 {
        print("Превышено 15, остановка")
        break
    }
    
    print("{i}")
}

// Меченые циклы
внешний: for i in 1..=3 {
    for j in 1..=3 {
        if i * j > 6 {
            print("Произведение превышает 6, прерывание внешнего цикла")
            break внешний
        }
        print("{i} × {j} = {i * j}")
    }
}

🎭 Сопоставление образцов (match)

Базовый оператор match

let деньНедели = "понедельник"

match деньНедели {
    case "понедельник" => print("Начало недели!")
    case "пятница" => print("Слава пятнице!")
    case "суббота" | "воскресенье" => print("Выходные!")
    case _ => print("Обычный день")
}

// match, возвращающий значение
let типДня = match деньНедели {
    case "понедельник" | "вторник" | "среда" | "четверг" | "пятница" => "рабочий день"
    case "суббота" | "воскресенье" => "выходной"
    case _ => "неизвестно"
}

print("Сегодня {типДня}")

Сопоставление чисел

let оценка = 87

let буквеннаяОценка = match оценка {
    case 90..=100 => "A"
    case 80..=89 => "B"
    case 70..=79 => "C"
    case 60..=69 => "D"
    case _ => "F"
}

// Использование условий-ограждений
let评价 = match оценка {
    case x if x >= 95 => "Идеальный результат!"
    case x if x >= 90 => "Отличная работа"
    case x if x >= 80 => "Хороший результат"
    case x if x >= 70 => "Средний уровень"
    case x if x >= 60 => "Сдано"
    case _ => "Требуется пересдача"
}

print("Оценка: {оценка}, Буквенная оценка: {буквеннаяОценка}, Оценка: {评价}")

Сопоставление структур/объектов

let пользователь = {
    имя: "ТопазДев",
    возраст: 25,
    работа: "разработчик",
    местоположение: "Москва"
}

// Деструктурирующее сопоставление
match пользователь {
    case { имя: "ТопазДев", возраст, работа: "разработчик" } => {
        print("Разработчик на Топазе, возраст: {возраст}")
    }
    case { возраст: пользовательскийВозраст, местоположение: "Москва" } if пользовательскийВозраст < 30 => {
        print("Молодой пользователь в Москве")
    }
    case { работа: "разработчик", местоположение } => {
        print("Разработчик в {местоположение}")
    }
    case _ => {
        print("Обычный пользователь")
    }
}

// Сопоставление вложенных объектов
let заказ = {
    клиент: { имя: "ПользовательТопаз", vip: true },
    товары: ["ноутбук", "мышь"],
    общаяСумма: 1500000
}

match заказ {
    case { клиент: { vip: true }, общаяСумма: сумма } if сумма > 1000000 => {
        print("Крупный заказ VIP-клиента: {сумма} рублей")
    }
    case { клиент: { имя }, товары } if товары.length() > 1 => {
        print("Заказ {имя} с несколькими товарами")
    }
    case _ => {
        print("Обычный заказ")
    }
}

Сопоставление массивов

let числа = [1, 2, 3, 4, 5]

match числа {
    case [] => print("Пустой массив")
    case [первый] => print("Один элемент: {первый}")
    case [первый, второй] => print("Два элемента: {первый}, {второй}")
    case [первый, ...остальные] => {
        print("Первый: {первый}, Остальные: {остальные}")
    }
}

// Специфичное сопоставление образцов
let списокОценок = [95, 87, 92]

match списокОценок {
    case [100, ...] => print("Начинается с идеальной оценки!")
    case [..., 100] => print("Заканчивается идеальной оценкой!")
    case [a, b, c] if a > 90 && b > 90 && c > 90 => print("Все оценки выше 90!")
    case оценки if оценки.all(x => x >= 80) => print("Все оценки выше 80")
    case _ => print("Обычное распределение оценок")
}

Сопоставление перечислений (enum)

enum Статус {
    Ожидание,
    Обработка(прогресс: int),
    Завершено(результат: string),
    Ошибка(сообщение: string)
}

let текущийСтатус = Статус.Обработка(прогресс: 75)

match текущийСтатус {
    case Статус.Ожидание => print("Ожидание...")
    case Статус.Обработка(прогресс: прогресс) => {
        print("Обработка: {прогресс}%")
        if прогресс > 50 {
            print("Более половины выполнено")
        }
    }
    case Статус.Завершено(результат: результат) => print("Завершено: {результат}")
    case Статус.Ошибка(сообщение: ошибка) => print("Произошла ошибка: {ошибка}")
}

// Сопоставление типа Option
let опциональноеЗначение: Option<string> = Some("Топаз")

match опциональноеЗначение {
    case Some(значение) => print("Имеет значение: {значение}")
    case None => print("Нет значения")
}

// Сопоставление типа Result
function разделить(a: int, b: int) -> Result<int, string> {
    if b == 0 {
        return Err("Нельзя делить на ноль")
    }
    return Ok(a / b)
}

match разделить(10, 2) {
    case Ok(результат) => print("Результат деления: {результат}")
    case Err(ошибка) => print("Ошибка: {ошибка}")
}

🛡️ Условия-ограждения и продвинутые образцы

Сложные условия-ограждения

let температура = 25
let влажность = 60
let сезон = "лето"

match (температура, влажность, сезон) {
    case (t, h, "лето") if t > 30 && h > 70 => print("Очень жарко и влажно")
    case (t, h, "лето") if t > 25 && h < 50 => print("Тепло и сухо")
    case (t, _, "зима") if t < 0 => print("Очень холодно")
    case (t, h, _) if t >= 20 && t <= 25 && h >= 40 && h <= 60 => print("Приятная погода")
    case _ => print("Обычная погода")
}

Функциональное сопоставление образцов

// Рекурсивное сопоставление образцов для обработки списка
function суммаСписка(список: [int]) -> int {
    match список {
        case [] => 0
        case [первый, ...остальные] => первый + суммаСписка(остальные)
    }
}

// Обход бинарного дерева
enum Дерево<T> {
    Пустое,
    Узел(значение: T, левое: Дерево<T>, правое: Дерево<T>)
}

function обходДерева<T>(дерево: Дерево<T>) {
    match дерево {
        case Дерево.Пустое => {
            // Ничего не делаем
        }
        case Дерево.Узел(значение: значение, левое: левое, правое: правое) => {
            обходДерева(левое)
            print("Значение узла: {значение}")
            обходДерева(правое)
        }
    }
}

print("Сумма списка: {суммаСписка([1, 2, 3, 4, 5])}")  // 15

⚡ Продвинутые образцы потока управления

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

let списокЗадач = [
    { тип: "email", приоритет: 1, содержание: "Проверить расписание встреч" },
    { тип: "звонок", приоритет: 3, содержание: "Консультация клиента" },
    { тип: "документ", приоритет: 2, содержание: "Написать отчет" }
]

for задача in списокЗадач {
    match задача {
        case { тип: "email", приоритет: 1, содержание } => {
            print("Срочная обработка email: {содержание}")
        }
        case { тип: типЗадачи, приоритет, содержание } if приоритет <= 2 => {
            print("Важная задача {типЗадачи}: {содержание}")
        }
        case { тип, содержание } => {
            print("Обычная задача {тип}: {содержание}")
        }
    }
}

Обработка ошибок и поток управления

// Обработка ошибок в стиле try-catch
function безопасноеЧтениеФайла(имяФайла: string) -> Result<string, string> {
    if !имяФайла.endsWith(".txt") {
        return Err("Поддерживаются только текстовые файлы")
    }
    
    // Симуляция чтения файла
    if Math.random() > 0.7 {
        return Err("Файл не найден")
    }
    
    return Ok("Содержимое файла здесь")
}

// Поток управления с обработкой ошибок
for имяФайла in ["data.txt", "config.json", "readme.txt"] {
    match безопасноеЧтениеФайла(имяФайла) {
        case Ok(содержимое) => {
            print("Успешно прочитан: {имяФайла}")
            print("Содержимое: {содержимое}")
            // Продолжить к следующему файлу при успехе
        }
        case Err(сообщениеОшибки) => {
            print("Ошибка ({имяФайла}): {сообщениеОшибки}")
            if сообщениеОшибки.contains("поддерживаются") {
                print("Неподдерживаемый формат файла, пропускаем")
                continue  // Продолжить к следующему файлу
            } else {
                print("Критическая ошибка, остановка обработки")
                break     // Остановить всю обработку
            }
        }
    }
}

Цепочки условного выполнения

// Условное связывание
function обработатьПользователя(идПользователя: int) -> Result<string, string> {
    let данныеПользователя = match получитьПользователяИзБазы(идПользователя) {
        case Ok(данные) => данные
        case Err(ошибка) => return Err("Не удалось получить пользователя: {ошибка}")
    }
    
    let результатВалидации = match валидироватьПользователя(данныеПользователя) {
        case Ok(_) => ()
        case Err(ошибка) => return Err("Валидация не пройдена: {ошибка}")
    }
    
    let результатОбработки = match обработатьДанныеПользователя(данныеПользователя) {
        case Ok(результат) => результат
        case Err(ошибка) => return Err("Обработка не удалась: {ошибка}")
    }
    
    return Ok("Обработка завершена: {результатОбработки}")
}

// Монадический стиль связывания
function монадическаяОбработка(идПользователя: int) -> Result<string, string> {
    return получитьПользователяИзБазы(идПользователя)
        .andThen(валидироватьПользователя)
        .andThen(обработатьДанныеПользователя)
        .map(результат => "Обработка завершена: {результат}")
}

🎯 Оптимизация и лучшие практики

1. Оптимизация условных операторов

// Плохо: Вложенные условия
let оценка = 85
if оценка >= 90 {
    print("Оценка A")
} else {
    if оценка >= 80 {
        print("Оценка B")
    } else {
        if оценка >= 70 {
            print("Оценка C")
        } else {
            print("Оценка F")
        }
    }
}

// Хорошо: Использование match
let буквеннаяОценка = match оценка {
    case 90..=100 => "A"
    case 80..=89 => "B"
    case 70..=79 => "C"
    case _ => "F"
}
print("Оценка {буквеннаяОценка}")

2. Образец раннего возврата

function зарегистрироватьПользователя(имя: string, email: string, возраст: int) -> Result<string, string> {
    // Ранняя валидация и возврат
    if имя.length() == 0 {
        return Err("Требуется имя")
    }
    
    if !email.contains("@") {
        return Err("Требуется действительный email")
    }
    
    if возраст < 0 || возраст > 120 {
        return Err("Требуется действительный возраст")
    }
    
    // Обработка только при прохождении всех валидаций
    let пользователь = создатьНовогоПользователя(имя, email, возраст)
    return Ok("Регистрация пользователя завершена: {пользователь.id}")
}

3. Использование сопоставления образцов

// Выражение сложной бизнес-логики с помощью образцов
enum СтатусЗаказа {
    Создан,
    ОплатаЗавершена,
    Доставка,
    Доставлен,
    Отменен
}

function обработатьЗаказ(статус: СтатусЗаказа, суммаОплаты: int, этоVip: bool) -> string {
    match (статус, суммаОплаты, этоVip) {
        case (СтатусЗаказа.Создан, _, _) => "Пожалуйста, проведите оплату"
        case (СтатусЗаказа.ОплатаЗавершена, сумма, true) if сумма > 100000 => {
            "Подготовка экспресс-доставки для VIP-клиента"
        }
        case (СтатусЗаказа.ОплатаЗавершена, сумма, _) if сумма > 50000 => {
            "Подготовка обычной доставки"
        }
        case (СтатусЗаказа.ОплатаЗавершена, _, _) => "Подготовка стандартной доставки"
        case (СтатусЗаказа.Доставка, _, true) => "Служба отслеживания VIP-доставки"
        case (СтатусЗаказа.Доставка, _, _) => "В доставке"
        case (СтатусЗаказа.Доставлен, _, _) => "Доставка завершена"
        case (СтатусЗаказа.Отменен, _, _) => "Заказ отменен"
    }
}

Поток управления Топаз мощный и выразительный. Правильно комбинируйте условные операторы, циклы и сопоставление образцов, чтобы писать читаемый и поддерживаемый код! 🚀