# Условные конструкции и ветвление в Rust

> Изучите основы ветвления в Rust: блоки кода, выражения if-else, сопоставление шаблонов через if let и цепочки условий let-chains.

- **URL:** https://eagle2000.space/rust/rust-conditionals/
- **Date:** 2026-07-31

- **Tags:** rust, dev

---## Введение. Блок кода (Code Block) и выражения

Блок кода в Rust является фундаментальной синтаксической единицей. Он не просто группирует инструкции, но и сам по себе является выражением, возвращающим значение.

* **Синтаксис:** Ограничивается фигурными скобками `{ ... }`. Внутри блока может содержаться набор инструкций, завершающихся точкой с запятой `;`.
* **Возвращаемое значение:** 
  * Если последняя строка блока является выражением без точки с запятой в конце, её результат становится возвращаемым значением всего блока кода.
  * Если последняя строка завершается точкой с запятой `;` (или блок кода пуст), блок возвращает тип **`()`** (пустой кортеж / unit-тип).

Давайте изучим блоки кода, синтаксис `if-else` и сопоставления на интерактивных слайдах:


### 💻 Ветвление и блоки кода


#### Шаг 1

```rust
fn main() {
    // Блок кода вычисляется в значение последнего выражения
    let y = {
        let x = 1;
        let z = 2;
        x + z // Нет точки с запятой в конце -> возвращает 3
    };

    // Блок кода завершающийся точкой с запятой возвращает ()
    let u = {
        let x = 10;
        println!("x = {}", x);
    };

    println!("y = {}, u = {:?}", y, u);
}
```

**Блоки кода (Code Blocks)**
- Блок кода ограничивается фигурными скобками `{}`.
- Если последнее выражение блока не заканчивается `;`, его результат возвращается из блока.
- Блок кода, оканчивающийся на `;`, или пустой блок возвращает unit-тип `()`.


#### Шаг 2

```rust
fn main() {
    let x = 150;

    // В Rust if-else является выражением и может возвращать значение
    let y = if x > 100 {
        let val = 2024;
        val
    } else {
        let val = 2025;
        val
    };

    println!("y = {}", y);

    // ОШИБКА КОМПИЛЯЦИИ: типы веток if-else должны быть одинаковыми!
    // let z = if x > 100 { 2024 } else { "2025" };
}
```

**Условные выражения if-else**
- Круглые скобки вокруг условия ставить не нужно (например, `if x > 100` вместо `if (x > 100)`).
- Условие обязано возвращать строго логический тип `bool`.
- Ветви `if` и `else` обязаны возвращать значения одного и того же типа. В Rust нет классического тернарного оператора, его роль играет `if-else`.


#### Шаг 3

```rust
fn main() {
    let some_val: Option<i32> = Some(150);

    // Использование if let для простого сопоставления с шаблоном
    if let Some(x) = some_val {
        println!("Совпало! x = {}", x);
    }

    let another_val: Option<i32> = Some(50);

    // Начиная с Rust 1.88 поддерживаются цепочки if let с && (let_chains)
    if let Some(x) = some_val && let Some(y) = another_val && x > y {
        println!("Обе переменные извлечены, и x ({}) > y ({})", x, y);
    }
}
```

**Конструкция if let и цепочки условий**
- `if let` — лаконичный аналог `match` для проверки соответствия конкретному шаблону.
- Переменная, связанная в шаблоне, видна только внутри блока `if let`.
- В современных версиях Rust (начиная с 1.88) можно комбинировать несколько `let` и логических выражений через `&&`.


---

## Условные конструкции и ветвление

### Базовое выражение `if` и `else`

Конструкция `if` проверяет истинность условия и выполняет соответствующую ветку кода.

* **Правила синтаксиса:**
  * Выражение условия **не нужно** оборачивать в круглые скобки `( )`. Использование круглых скобок вокруг самого выражения условия (например, `if (a > 5)`) считается нарушением стиля.
  * Результат условного выражения строго обязан иметь тип **`bool`**. Использование целых чисел (как в C/C++) приведет к ошибке компиляции.

```rust
// ОШИБКА КОМПИЛЯЦИИ: count имеет тип отличный от bool
if count { ... } 

// КОРРЕКТНО: выражения возвращают bool
if count > 0 { ... }
if count != 0 { ... }
```

### Операторы сравнения и логические операторы

Используются для формирования условных выражений:
* `>` (больше), `>=` (больше либо равно)
* `<` (меньше), `<=` (меньше либо равно)
* `==` (равенство), `!=` (неравенство)
* `&&` (логическое И), `||` (логическое ИЛИ)

### `if` как выражение (Assigning from `if`)

В Rust `if-else` является выражением, а значит, может возвращать значение, которое можно присвоить переменной.

* **Критическое правило типов:** Все ветви конструкции `if-else` при использовании в качестве выражения **обязаны возвращать один и тот же тип данных**.
* В Rust нет классического тернарного оператора `? :`. Вместо него используется `if-else`.

```rust
// Корректно: обе ветки возвращают i32
let y = if x > 100 { 2024 } else { 2025 }; 

// ОШИБКА КОМПИЛЯЦИИ (Несовпадение типов: i32 и &str):
let y = if x > 100 { 2024 } else { "2025" }; 
```

Если ветка `else` отсутствует, то выражение `if` обязано возвращать unit-тип `()`, так как если условие не выполнится, результатом по умолчанию будет `()`:

```rust
let u = if x > 100 { foo() }; // Допустимо, только если foo() возвращает ()
```

---

## Конструкция `if let` и сопоставление с шаблоном

### Базовый `if let`

Используется как лаконичная альтернатива `match`, когда нас интересует только один конкретный шаблон.

```rust
// Для Option
if let Some(x) = foo_opt() {
    bar(x); // x доступен только внутри этого блока
} else {
    // Выполняется, если результат None
}
```

### Цепочки `if let` (let-chains)

Начиная с версии **Rust 1.88**, поддерживается синтаксис объединения нескольких `let`-шаблонов и логических условий через оператор `&&` в одном выражении `if`.

```rust
// Сопоставление с шаблоном + дополнительное ограничение на переменную x
if let Some(x) = foo() && x > 100 {
    todo!()
}

// Множественные сопоставления с шаблонами в одном условии
if let Some(x) = foo() && let Some(y) = bar() && x > y {
    todo!()
}
```

---

## Проверь свои знания!

Пройдите короткий интерактивный тест, чтобы закрепить понимание блоков кода и ветвлений в Rust.


### 📝 Условные конструкции в Rust


**1. Что возвращает блок кода `{ let x = 5; x * 2; }`?**

- [ ] 10
- [ ] 5
- [ ] Пустой кортеж `()` (unit-тип)
- [ ] Ошибку компиляции из-за отсутствия явного return

**2. Какое из следующих условий в конструкции `if` вызовет ошибку компиляции?**

- [ ] if x != 0 { ... }
- [ ] if x { ... } (где x равен 1 типа i32)
- [ ] if x > 5 && y < 10 { ... }
- [ ] if true { ... }

**3. Какое критическое требование предъявляется к веткам `if-else`, когда они используются как выражение?**

- [ ] Они обязаны возвращать целочисленный тип
- [ ] Они должны быть заключены в круглые скобки
- [ ] Обе ветки (if и else) обязаны возвращать значение одного и того же типа
- [ ] Ветка else должна отсутствовать

**4. Что возвращает выражение `let u = if x > 100 { foo() };` если foo() возвращает i32 и x равен 50?**

- [ ] 0
- [ ] Option::None
- [ ] Ошибку компиляции (типы не совпадают)
- [ ] i32

**5. Какое логическое выражение объединяет несколько шаблонов `let` и условий в цепочке `if let`?**

- [ ] || (ИЛИ)
- [ ] && (И)
- [ ] , (запятая)
- [ ] and

