% Циклы
На данный момент в Rust есть три способа организовать циклическое исполнение
кода. Это loop
, while
и for
. У каждого подхода своё применение.
Бесконечный цикл (loop
) — простейшая форма цикла в Rust. С помощью этого
ключевого слова можно организовать цикл, который продолжается, пока не
выполнится какой-либо оператор, прерывающий его. Бесконечный цикл в Rust
выглядит так:
loop {
println!("Зациклились!");
}
Цикл 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
завершается.
Если вам нужен бесконечный цикл, то можете сделать условие всегда истинным:
while true {
Однако, для такого случая в Rust имеется ключевое слово loop
:
loop {
В Rust анализатор потока управления обрабатывает конструкцию loop
иначе, чем
while true
, хотя для нас это одно и тоже. На данном этапе изучения Rust нам не
важно знать в чем именно различие между этими конструкциями, но если вы хотите
сделать бесконечный цикл, то используйте конструкцию loop
. Компилятор
сможет транслировать ваш код в более эффективный и безопасный машинный код.
Цикл for
нужен для повторения блока кода определённое количество раз. Циклы
for
в Rust работают немного иначе, чем в других языках программирования.
Например в Си-подобном языке цикл for
выглядит так:
for (x = 0; x < 10; x++) {
printf( "%d\n", x );
}
Однако, этот код в Rust будет выглядеть следующим образом:
for x in 0..10 {
println!("{}", x); // x: i32
}
Можно представить цикл более абстрактно:
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
Не забудьте написать скобки вокруг интервала.
let lines = "привет\nмир\nhello\nworld".lines();
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);
}
}