Введение
В этом практическом занятии мы узнаем, как использовать циклы for и диапазоны в Rust. Мы можем использовать цикл for вместе с записью диапазона a..b, чтобы перебирать диапазон значений. Например, мы можем написать программу FizzBuzz с использованием цикла for вместо цикла while. Кроме того, мы можем использовать запись ..=, чтобы указать диапазон, включающий оба конца. Цикл for также может взаимодействовать с итераторами по-разному, например, с использованием iter, чтобы взять в долг каждый элемент коллекции, into_iter, чтобы потребовать коллекцию, или iter_mut, чтобы изменить каждый элемент коллекции. Каждый из этих методов предоставляет другой вид данных внутри коллекции, что позволяет выполнять разные действия.
Примечание: Если практическое занятие не уточняет имя файла, вы можете использовать любое имя файла, которое хотите. Например, вы можете использовать
main.rs, скомпилировать и запустить его с помощьюrustc main.rs &&./main.
Циклы 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, это ключевой различия в типах итерации. Различие в типе, конечно же, предполагает разные действия, которые можно выполнять.
Резюме
Поздравляем! Вы завершили практическое занятие по циклам for. Вы можете выполнить больше практических занятий в LabEx, чтобы улучшить свои навыки.