Цикл for

for и диапазоны

Конструкция for in может быть использована для итерации по итераторам (Iterator). Один из самых простых способов создать итератор это использовать диапазон значений 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 может взаимодействовать с итератором разными способами. Как обсуждается далее про типаж Iterator, цикл 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!("Программисты Rust вокруг нас!"),
            _ => println!("Привет {}", name),
        }
    }
}
  • into_iter - эта функция потребляет коллекцию так что на каждой итерации предоставляются данные. Коллекция больше не доступна для использования так как владение ею перешло в эту функцию.
fn main() {
    let names = vec!["Bob", "Frank", "Ferris"];

    for name in names.into_iter() {
        match name {
            "Ferris" => println!("Программисты Rust вокруг нас!"),
            _ => println!("Привет {}", name),
        }
    }
}
  • iter_mut - эта функция делает изменяемое заимствование каждого элемента коллекции, позволяя изменять коллекцию на месте.
fn main() {
    let mut names = vec!["Bob", "Frank", "Ferris"];

    for name in names.iter_mut() {
        *name = match name {
            &mut "Ferris" => "Программисты Rust вокруг нас!",
            _ => "Привет",
        }
    }

    println!("имена: {:?}", names);
}

В вышеуказанных кусках кода, обратите внимание на ветку match, которая имеет ключевое отличие в зависимости от типа выполнения итераций. Разница в типе, конечно, подразумевает различные действия, которые могут быть выполнены.

Смотрите также:

Итераторы (Iterator)