Циклы и диапазоны в Rust

RustRustBeginner
Практиковаться сейчас

This tutorial is from open-source community. Access the source code

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом практическом занятии мы узнаем, как использовать циклы for и диапазоны в Rust. Мы можем использовать цикл for вместе с записью диапазона a..b, чтобы перебирать диапазон значений. Например, мы можем написать программу FizzBuzz с использованием цикла for вместо цикла while. Кроме того, мы можем использовать запись ..=, чтобы указать диапазон, включающий оба конца. Цикл for также может взаимодействовать с итераторами по-разному, например, с использованием iter, чтобы взять в долг каждый элемент коллекции, into_iter, чтобы потребовать коллекцию, или iter_mut, чтобы изменить каждый элемент коллекции. Каждый из этих методов предоставляет другой вид данных внутри коллекции, что позволяет выполнять разные действия.

Примечание: Если практическое занятие не уточняет имя файла, вы можете использовать любое имя файла, которое хотите. Например, вы можете использовать main.rs, скомпилировать и запустить его с помощью rustc main.rs &&./main.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/ControlStructuresGroup(["Control Structures"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/BasicConceptsGroup -.-> rust/mutable_variables("Mutable Variables") rust/DataTypesGroup -.-> rust/string_type("String Type") rust/ControlStructuresGroup -.-> rust/for_loop("for Loop") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") subgraph Lab Skills rust/variable_declarations -.-> lab-99308{{"Циклы и диапазоны в Rust"}} rust/mutable_variables -.-> lab-99308{{"Циклы и диапазоны в Rust"}} rust/string_type -.-> lab-99308{{"Циклы и диапазоны в Rust"}} rust/for_loop -.-> lab-99308{{"Циклы и диапазоны в Rust"}} rust/function_syntax -.-> lab-99308{{"Циклы и диапазоны в Rust"}} rust/expressions_statements -.-> lab-99308{{"Циклы и диапазоны в Rust"}} rust/method_syntax -.-> lab-99308{{"Циклы и диапазоны в Rust"}} end

Циклы 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, чтобы улучшить свои навыки.