На данный момент в Rust есть три способа организовать циклическое исполнение
кода. Это loop
, while
и for
. У каждого подхода своё применения.
loop
Бесконечный цикл (loop
) — простейшая форма цикла в Rust. С помощью этого
ключевого слова можно организовать цикл, который продолжается, пока не
выполнится какой-либо оператор, прерывающий его. Бесконечный цикл в Rust
выглядит так:
loop { println!("Зациклились!"); }
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; } }
Он применяется, если неизвестно, сколько раз нужно выполнить тело цикла, чтобы
получить результат. При каждой итерации цикла проверяется условие, и если оно
истинно, то запускается следующая итерация. Иначе цикл while
завершается.
Если вам нужен бесконечный цикл, то можете сделать условие всегда истинным:
fn main() { while true { }while true {
Однако, для такого случая в Rust имеется ключевое слово loop
:
loop {
В Rust анализатор потока управления обрабатывает конструкцию loop
иначе, чем
while true
, хотя для нас это одно и тоже. На данном этапе изучения Rust нам не
важно знать в чем именно различие между этими конструкциями, но если вы хотите
сделать бесконечный цикл, то используйте конструкцию loop
. Компилятор
сможет транслировать ваш код в более эффективный и безопасный машинный код.
for
Цикл for
нужен для повторения блока кода определённое количество раз. Циклы
for
в Rust работают немного иначе, чем в других языках программирования.
Например в Си-подобном языке цикл for
выглядит так:
for (x = 0; x < 10; x++) {
printf( "%d\n", x );
}
Однако, этот код в Rust будет выглядеть следующим образом:
fn main() { for x in 0..10 { println!("{}", x); // x: i32 } }for x in 0..10 { println!("{}", x); // x: i32 }
Можно представить цикл более абстрактно:
fn main() { for переменная in выражение { тело_цикла } }for переменная in выражение { тело_цикла }
Выражение — это итератор. Их мы будем рассматривать позже в этом
руководстве. Итератор возвращает серию элементов, где каждый элемент будет
являться одной итерацией цикла. Значение этого элемента затем присваивается
переменной
, которая будет доступна в теле цикла. После окончания тела цикла,
берётся следующее значение итератора и снова выполняется тело цикла. Когда в
итераторе закончатся значения, цикл for
завершается.
В нашем примере, 0..10
— это выражение, которое задаёт начальное и конечное
значение, и возвращает итератор. Обратите внимание, что конечное значение не
включается в него. В нашем примере будут напечатаны числа от 0
до 9
, но не
будет напечатано 10
.
В Rust намеренно нет цикла for
в стиле C. Управлять каждым элементом цикла
вручную сложно, и это может приводить к ошибкам даже у опытных программистов на
C.
Если вы хотите отслеживать число прошедших итераций, используйте функцию
.enumerate()
.
for (i,j) in (5..10).enumerate() { println!("i = {} и j = {}", i, j); }
Выводит:
i = 0 и j = 5
i = 1 и j = 6
i = 2 и j = 7
i = 3 и j = 8
i = 4 и j = 9
Не забудьте написать скобки вокруг интервала.
for (linenumber, line) in lines.enumerate() { println!("{}: {}", linenumber, line); }
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; } }
В этом примере в условии для выхода из цикла используется изменяемое имя done
логического типа. В Rust имеются два ключевых слова, которые помогают работать с
итерациями цикла: break
и continue
.
Мы можем переписать цикл с помощью break
, чтобы избавиться от переменной
done
:
let mut x = 5; loop { x += x - 3; println!("{}", x); if x % 5 == 0 { break; } }
Теперь мы используем бесконечный цикл loop
и break
для выхода из цикла.
Использование явного return
также остановит выполнение цикла.
continue
похож на break
, но вместо выхода из цикла переходит к следующей
итерации. Следующий пример отобразит только нечётные числа:
for x in 0..10 { if x % 2 == 0 { continue; } println!("{}", x); }
Когда у вас много вложенных циклов, вы можете захотеть указать, к какому именно
циклу относится 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); } }