1. 1. Introduction
  2. 2. Введение
  3. 3. C чего начать
  4. 4. Изучение Rust
    1. 4.1. Угадайка
    2. 4.2. Обедающие философы
    3. 4.3. Вызов кода на Rust из других языков
  5. 5. Синтаксис и семантика
    1. 5.1. Связывание имён
    2. 5.2. Функции
    3. 5.3. Простые типы
    4. 5.4. Комментарии
    5. 5.5. Конструкция `if`
    6. 5.6. Циклы
    7. 5.7. Владение
    8. 5.8. Ссылки и заимствование
    9. 5.9. Время жизни
    10. 5.10. Изменяемость
    11. 5.11. Структуры
    12. 5.12. Перечисления
    13. 5.13. Конструкция `match`
    14. 5.14. Шаблоны сопоставления `match`
    15. 5.15. Синтаксис методов
    16. 5.16. Вектора
    17. 5.17. Строки
    18. 5.18. Обобщённое программирование
    19. 5.19. Типажи
    20. 5.20. Типаж `Drop`
    21. 5.21. Конструкция `if let`
    22. 5.22. Типажи-объекты
    23. 5.23. Замыкания
    24. 5.24. Универсальный синтаксис вызова функций
    25. 5.25. Контейнеры и модули
    26. 5.26. `const` и `static`
    27. 5.27. Атрибуты
    28. 5.28. Псевдонимы типов
    29. 5.29. Приведение типов
    30. 5.30. Ассоциированные типы
    31. 5.31. Безразмерные типы
    32. 5.32. Перегрузка операций
    33. 5.33. Преобразования при разыменовании
    34. 5.34. Макросы
    35. 5.35. Сырые указатели
    36. 5.36. Небезопасный код
  6. 6. Эффективное использование Rust
    1. 6.1. Стек и куча
    2. 6.2. Тестирование
    3. 6.3. Условная компиляция
    4. 6.4. Документация
    5. 6.5. Итераторы
    6. 6.6. Многозадачность
    7. 6.7. Обработка ошибок
    8. 6.8. Выбор гарантий
    9. 6.9. Интерфейс внешних функций
    10. 6.10. Типажи `Borrow` и `AsRef`
    11. 6.11. Каналы сборок
    12. 6.12. Using Rust without the standard library
  7. 7. Нестабильные возможности Rust
    1. 7.1. Плагины к компилятору
    2. 7.2. Встроенный ассемблерный код
    3. 7.3. Без stdlib
    4. 7.4. Внутренние средства
    5. 7.5. Элементы языка
    6. 7.6. Продвинутое руководство по компоновке
    7. 7.7. Тесты производительности
    8. 7.8. Синтаксис упаковки и шаблоны `match`
    9. 7.9. Шаблоны `match` для срезов
    10. 7.10. Ассоциированные константы
    11. 7.11. Пользовательские менеджеры памяти
  8. 8. Глоссарий
  9. 9. Syntax Index
  10. 10. Библиография

Циклы

На данный момент в Rust есть три способа организовать циклическое исполнение кода. Это loop, while и for. У каждого подхода своё применение.

Циклы loop

Бесконечный цикл (loop) — простейшая форма цикла в Rust. С помощью этого ключевого слова можно организовать цикл, который продолжается, пока не выполнится какой-либо оператор, прерывающий его. Бесконечный цикл в Rust выглядит так:

loop {
    println!("Зациклились!");
}Run

Циклы while

Цикл while — это ещё один вид конструкции цикла в Rust. Выглядит он так:

let mut x = 5; // mut x: i32
let mut done = false; // mut done: bool

while !done {
    x += x - 3;

    println!("{}", x);

    if x % 5 == 0 {
        done = true;
    }
}Run

Он применяется, если неизвестно, сколько раз нужно выполнить тело цикла, чтобы получить результат. При каждой итерации цикла проверяется условие, и если оно истинно, то запускается следующая итерация. Иначе цикл while завершается.

Если вам нужен бесконечный цикл, то можете сделать условие всегда истинным:

while true {Run

Однако, для такого случая в Rust имеется ключевое слово loop:

loop {Run

В Rust анализатор потока управления обрабатывает конструкцию loop иначе, чем while true, хотя для нас это одно и тоже. На данном этапе изучения Rust нам не важно знать в чем именно различие между этими конструкциями, но если вы хотите сделать бесконечный цикл, то используйте конструкцию loop. Компилятор сможет транслировать ваш код в более эффективный и безопасный машинный код.

Циклы for

Цикл for нужен для повторения блока кода определённое количество раз. Циклы for в Rust работают немного иначе, чем в других языках программирования. Например в Си-подобном языке цикл for выглядит так:

for (x = 0; x < 10; x++) {
    printf( "%d\n", x );
}

Однако, этот код в Rust будет выглядеть следующим образом:

for x in 0..10 {
    println!("{}", x); // x: i32
}Run

Можно представить цикл более абстрактно:

for переменная in выражение {
    тело_цикла
}Run

Выражение — это итератор. Их мы будем рассматривать позже в этом руководстве. Итератор возвращает серию элементов, где каждый элемент будет являться одной итерацией цикла. Значение этого элемента затем присваивается переменной, которая будет доступна в теле цикла. После окончания тела цикла, берётся следующее значение итератора и снова выполняется тело цикла. Когда в итераторе закончатся значения, цикл for завершается.

В нашем примере, 0..10 — это выражение, которое задаёт начальное и конечное значение, и возвращает итератор. Обратите внимание, что конечное значение не включается в него. В нашем примере будут напечатаны числа от 0 до 9, но не будет напечатано 10.

В Rust намеренно нет цикла for в стиле C. Управлять каждым элементом цикла вручную сложно, и это может приводить к ошибкам даже у опытных программистов на C.

Перечисление

Если вы хотите отслеживать число прошедших итераций, используйте функцию .enumerate().

С интервалами

for (i,j) in (5..10).enumerate() {
    println!("i = {} и j = {}", i, j);
}Run

Выводит:

i = 0 и j = 5
i = 1 и j = 6
i = 2 и j = 7
i = 3 и j = 8
i = 4 и j = 9

Не забудьте написать скобки вокруг интервала.

С итераторами

let lines = "привет\nмир\nhello\nworld".lines();
for (linenumber, line) in lines.enumerate() {
    println!("{}: {}", linenumber, line);
}Run

Outputs:

0: привет
1: мир
2: hello
3: world

Раннее прерывание цикла

Давайте ещё раз посмотрим на цикл while:

let mut x = 5;
let mut done = false;

while !done {
    x += x - 3;

    println!("{}", x);

    if x % 5 == 0 {
        done = true;
    }
}Run

В этом примере в условии для выхода из цикла используется изменяемое имя done логического типа. В Rust имеются два ключевых слова, которые помогают работать с итерациями цикла: break и continue.

Мы можем переписать цикл с помощью break, чтобы избавиться от переменной done:

let mut x = 5;

loop {
    x += x - 3;

    println!("{}", x);

    if x % 5 == 0 { break; }
}Run

Теперь мы используем бесконечный цикл loop и break для выхода из цикла. Использование явного return также остановит выполнение цикла.

continue похож на break, но вместо выхода из цикла переходит к следующей итерации. Следующий пример отобразит только нечётные числа:

for x in 0..10 {
    if x % 2 == 0 { continue; }

    println!("{}", x);
}Run

Метки циклов

Когда у вас много вложенных циклов, вы можете захотеть указать, к какому именно циклу относится break или continue. Как и во многих других языках, по умолчанию эти операторы будут относиться к самому внутреннему циклу. Если вы хотите прервать внешний цикл, вы можете использовать метку. Так, этот код будет печатать на экране только когда и x, и y нечётны:

'outer: for x in 0..10 {
    'inner: for y in 0..10 {
        if x % 2 == 0 { continue 'outer; } // продолжает цикл по x
        if y % 2 == 0 { continue 'inner; } // продолжает цикл по y
        println!("x: {}, y: {}", x, y);
    }
}Run