Циклы for
for и диапазон
Конструкция for in
может использоваться для перебора Итератора
. Одним из самых простых способов создания итератора является использование записи диапазона a..b
. Это генерирует значения от a
(включительно) до b
(исключительно) с шагом в единицу.
Напишем FizzBuzz с использованием for
вместо while
.
fn main() {
// `n` примет значения: 1, 2,..., 100 на каждой итерации
for n in 1..101 {
if n % 15 == 0 {
println!("fizzbuzz");
} else if n % 3 == 0 {
println!("fizz");
} else if n % 5 == 0 {
println!("buzz");
} else {
println!("{}", n);
}
}
}
Вместо этого, a..=b
можно использовать для диапазона, который включает оба конца. Вышеперечисленное можно записать так:
fn main() {
// `n` примет значения: 1, 2,..., 100 на каждой итерации
for n in 1..=100 {
if n % 15 == 0 {
println!("fizzbuzz");
} else if n % 3 == 0 {
println!("fizz");
} else if n % 5 == 0 {
println!("buzz");
} else {
println!("{}", n);
}
}
}
for и итераторы
Конструкция for in
способна взаимодействовать с Итератором
несколькими способами. Как обсуждалось в разделе о трейте Итератор
, по умолчанию цикл for
применяет функцию into_iter
к коллекции. Однако это не единственный способ преобразования коллекций в итераторы.
into_iter
, iter
и iter_mut
все обрабатывают преобразование коллекции в итератор по-разному, предоставляя разные представления о данных внутри.
iter
- Это берёт каждый элемент коллекции на каждой итерации. Таким образом, коллекция остаётся неизменной и доступной для повторного использования после цикла.
fn main() {
let names = vec!["Bob", "Frank", "Ferris"];
for name in names.iter() {
match name {
&"Ferris" => println!("There is a rustacean among us!"),
// TODO ^ Попробуйте удалить & и сопоставить только "Ferris"
_ => println!("Hello {}", name),
}
}
println!("names: {:?}", names);
}
into_iter
- Это потребляет коллекцию, так что на каждой итерации предоставляется именно тот же набор данных. Как только коллекция потреблена, она больше не доступна для повторного использования, так как она была «перемещена» внутри цикла.
fn main() {
let names = vec!["Bob", "Frank", "Ferris"];
for name in names.into_iter() {
match name {
"Ferris" => println!("There is a rustacean among us!"),
_ => println!("Hello {}", name),
}
}
println!("names: {:?}", names);
// FIXME ^ Закомментируйте эту строку
}
iter_mut
- Это изменяет каждый элемент коллекции, позволяя изменять коллекцию на месте.
fn main() {
let mut names = vec!["Bob", "Frank", "Ferris"];
for name in names.iter_mut() {
*name = match name {
&mut "Ferris" => "There is a rustacean among us!",
_ => "Hello",
}
}
println!("names: {:?}", names);
}
В вышеперечисленных фрагментах обратите внимание на тип ветви match
, это ключевой различия в типах итерации. Различие в типе, конечно же, предполагает разные действия, которые можно выполнять.