В функциональном стиле, когда тебе нужно свести последовательность значений к одному числу (произведению в данном случае), используют **свертку** (fold) или, в более простых случаях, готовые методы агрегации вроде `product`.

В Rust у итераторов есть метод `product()`, который делает ровно то, что нужно для факториала.

### Решение 1: Самое идиоматичное (Iterators + product)

Мы создаем диапазон от `1` до `num` (включительно) и перемножаем все числа.

```rust
fn factorial(num: u64) -> u64 {
    (1..=num).product()
}
```

**Почему это работает:**
1.  `(1..=num)` создает итератор, генерирующий числа `1, 2, 3, ..., num`.
    *   Если `num` равно `0`, диапазон `1..=0` пуст.
2.  `.product()` проходит по итератору, умножая аккумулятор на каждый элемент.
    *   Для пустого итератора (факториал 0) `product()` возвращает мультипликативную единицу (`1`), что математически верно: $0! = 1$.

***

### Решение 2: Более явное (Fold)

Если бы метода `product()` не существовало, мы бы использовали `fold`. Это классическая "reduce" операция из функционального программирования.

```rust
fn factorial(num: u64) -> u64 {
    (1..=num).fold(1, |acc, x| acc * x)
}
```

**Разбор:**
*   `1` (первый аргумент) — начальное значение аккумулятора.
*   `|acc, x| acc * x` — замыкание, которое берет текущий аккумулятор (`acc`) и следующий элемент (`x`), и возвращает новое значение аккумулятора.
*   Для `num = 4`:
    1.  `acc = 1` (начальное), `x = 1` -> `1 * 1 = 1`
    2.  `acc = 1`, `x = 2` -> `1 * 2 = 2`
    3.  `acc = 2`, `x = 3` -> `2 * 3 = 6`
    4.  `acc = 6`, `x = 4` -> `6 * 4 = 24`

**Итог:**
Используй `(1..=num).product()` — это самый "ржавый" (Rustacean) и читаемый способ. Он выполняет все твои условия:
*   Нет явного `return` (это выражение).
*   Нет циклов `for/while` (спрятаны внутри итератора).
*   Нет мутабельных переменных.
*   Нет рекурсии.
  
  
  ### 1. "Джентльменский набор" итераторов
Помимо уже знакомых тебе `map`, `filter`, `fold` и `flat_map`, вот что ты будешь использовать в 90% случаев:

*   **`collect()`** — ты уже знаешь, это "материализатор". Превращает поток обратно в коллекцию (`Vec`, `HashMap`, `String`...).
*   **`find(|x| ...)`** — ищет **первый** элемент, удовлетворяющий условию. Возвращает `Option<T>`.
*   **`any(|x| ...)` / `all(|x| ...)`** — возвращают `bool`. `any` проверяет, есть ли *хотя бы один*, `all` — что *все* соответствуют.
*   **`enumerate()`** — добавляет индекс к элементу. Вместо `x` получаешь `(index, x)`.
    ```rust
    // Вывести строки с номерами
    lines.iter().enumerate().for_each(|(i, line)| println!("{}: {}", i, line));
    ```
*   **`zip(other_iter)`** — "сшивает" два итератора в один поток пар `(a, b)`.
*   **`take(n)` / `skip(n)`** — берет первые `n` или пропускает первые `n` элементов.
*   **`chain(other_iter)`** — склеивает два итератора: "сначала всё из первого, потом всё из второго".
*   **`inspect(|x| ...)`** — бесценно для отладки! Позволяет "подсмотреть" значение в середине цепочки, не меняя его (обычно там делают `println!`).

### 2. Вся ли функциональщина в Rust — это итераторы?
И да, и нет.
*   **Да**, итераторы — это главный локомотив функционального стиля в Rust. Это самый мощный и оптимизированный инструмент для обработки данных.
*   **Нет**, ФП в Rust шире. Оно включает:
    *   **Enum + Pattern Matching** (алгебраические типы данных) — это основа логики, замена классам и полиморфизму.
    *   **Immutability** (неизменяемость по умолчанию).
    *   **Closures** (замыкания) — функции высшего порядка, которые можно передавать и возвращать.

Но именно цепочки итераторов делают код "визуально функциональным".

### 3. Каждую ли задачу можно решить функционально?
**Теоретически — да.** Любой цикл можно переписать через рекурсию или `fold`.
**Практически — не стоит.**

Rust — прагматичный язык. Иногда **императивный код лучше**:
1.  **Сложная мутация состояния**: Если тебе нужно обновлять 5 разных переменных в зависимости от сложной логики на каждом шаге, `fold` превратится в ад с кортежем из 5 элементов. Обычный `for` будет чище.
2.  **Ранний выход из вложенных циклов**: Выйти из тройного вложенного цикла через `break 'label` проще, чем писать цепочку итераторов, которая умеет прерываться.
3.  **Графы и произвольный доступ**: Итераторы хороши для *последовательностей*. Если ты прыгаешь по индексам массива туда-сюда (`i`, `i+5`, `i/2`), функциональный стиль будет выглядеть как натягивание совы на глобус.

**Совет:** Используй итераторы для *трансформации потоков данных* (фильтрация, маппинг, поиск, агрегация). Используй циклы для *сложного управления потоком выполнения* или когда состояние слишком запутанное. В Rust нормально сочетать оба подхода.