Работа с итератори

12 ноември 2024

Административни неща

Преговор

Итератори

1 2 3 4 5 6 7 8 9
pub trait Iterator {
    type Item;

    // Required method
    fn next(&mut self) -> Option<Self::Item>;

    // Provided methods
    // ...75 methods
}

Итератори

1 2 3
for word in &["foo", "bar", "baz"] {
    println!("{}", word);
}
foo bar baz
fn main() {
for word in &["foo", "bar", "baz"] {
    println!("{}", word);
}
}

Итератори

1 2 3
for n in 1.. {
    println!("{n} mississippi");
}
fn main() {
for n in 1.. {
    println!("{n} mississippi");
}
}

Разгъване на for-цикъл

1 2 3 4 5 6 7 8 9 10 11 12 13 14
for loop_variable in iterator {
    code();
}

{
    let mut iter = IntoIterator::into_iter(iterator);
    loop {
        match iter.next() {
            None => break,
            Some(loop_variable) => { code(); },
        };
    }
}
result

trait IntoIterator

Указва, че даден тип може да се конвертира до итератор

1 2 3 4 5 6
pub trait IntoIterator {
    type Item;
    type IntoIter: Iterator<Item = Self::Item>;

    fn into_iter(self) -> Self::IntoIter;
}

trait IntoIterator

Вектора може да се превърне в итератор.
Това консумира вектора - итератора връща един по един елементите по стойност

1 2 3 4 5 6 7 8
impl<T, A: Allocator> IntoIterator for Vec<T, A> {
    type Item = T;
    type IntoIter = std::vec::IntoIter<T, A>;

    fn into_iter(self) -> Self::IntoIter {
        /* ... */
    }
}

trait IntoIterator

Еквивалентно е дали ще итерираме по vec или vec.into_iter()

1 2 3 4 5
for val in vec {
}

for val in vec.into_iter() {
}

trait IntoIterator

Еквивалентно е дали ще итерираме по vec или vec.into_iter()

1 2 3 4 5 6
for val in vec {
-> for val in IntoIterator::into_iter(vec)

for val in vec.into_iter()
-> for val in IntoIterator::into_iter(vec.into_iter())
-> for val in IntoIterator::into_iter(<Vec<_> as IntoIterator>::into_iter(vec))

trait IntoIterator

Защото std::vec::IntoIter е Iterator, а всеки итератор имплементира IntoIterator

1 2 3 4 5 6 7 8
impl<I: Iterator> IntoIterator for I {
    type Item = I::Item;
    type IntoIter = I;

    fn into_iter(self) -> I {
        self
    }
}

trait IntoIterator

1 2 3 4 5
vec                          // std::vec::Vec<Foo>
IntoIterator::into_iter(vec) // std::vec::IntoIter<Foo>

vec.into_iter()                          // std::vec::IntoIter<Foo>
IntoIterator::into_iter(vec.into_iter()) // std::vec::IntoIter<Foo>

IntoIterator за референции

Също така е еквиваленто дали ще итерираме по &vec или vec.iter()

1 2 3 4 5
for val in &vec {
}

for val in vec.iter() {
}

IntoIterator за референции

IntoIterator за референции

Не, защото има отделна имплементация на IntoIterator за референция към вектор

1 2 3 4 5 6 7 8
impl<'a, T, A: Allocator> IntoIterator for &'a Vec<T, A> {
    type Item = &'a T;
    type IntoIter = std::slice::Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

IntoIterator за референции

И за mutable референция към вектор

1 2 3 4 5 6 7 8
impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A> {
    type Item = &'a mut T;
    type IntoIter = std::slice::IterMut<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter_mut()
    }
}

IntoIterator за референции

1 2 3 4 5 6 7 8
IntoIterator::into_iter(vec) // -> std::vec::IntoIter<T>
                             // -> impl Iterator<Item = T>

IntoIterator::into_iter(&vec)  // -> std::slice::Iter<'a, T>
                               // -> impl Iterator<Item = &T>

IntoIterator::into_iter(&mut vec) // -> std::slice::IterMut<'a, T>
                                  // -> impl Iterator<Item = &mut T>

IntoIterator

Дали ще използвате &vec / &mut vec / vec.
Или iter() / iter_mut() / into_iter().
Е въпрос на лична преференция.

1 2 3 4 5 6 7
for val in &vec { /* ... */ }
for val in &mut vec { /* ... */ }
for val in vec { /* ... */ }

for val in vec.iter() { /* ... */ }
for val in vec.iter_mut() { /* ... */ }
for val in vec.into_iter() { /* ... */ }

Адаптери за итератори

Адаптери за итератори

Адаптери за итератори

Адаптери за итератори

Адаптери за итератори

map

Трансформира всяка стойност от итератора, използвайки функция T -> U

1 2 3
for num in [1, 2, 3].iter().map(|&x| x * x) {
    println!("{}", num);
}
1 4 9
fn main() {
for num in [1, 2, 3].iter().map(|&x| x * x) {
    println!("{}", num);
}
}

Адаптери за итератори

map

Функцията map връща структура std::iter::Map, която си запазва оригиналния итератор и функцията.

1 2 3 4 5 6 7
let nums = &[1, 2, 3];

let doubled = nums.iter().map(|&x| {
    x * x
});

println!("{:?}", doubled);
Map { iter: Iter([1, 2, 3]) }
fn main() {
let nums = &[1, 2, 3];

let doubled = nums.iter().map(|&x| {
    x * x
});

println!("{:?}", doubled);
}

Адаптери за итератори

map

Функцията map връща структура std::iter::Map, която си запазва оригиналния итератор и функцията.

1 2 3 4 5 6 7 8
let nums = &[1, 2, 3];

let doubled = nums.iter().map(|&x| {
    x * x
});

let () = doubled; // expected struct `Map<std::slice::Iter<'_, {integer}>, {closure@src/bin/main.rs:4:31: 4:35}>`
                  // found unit type `()`

Адаптери за итератори

map

Итераторите са мързеливи - извикването на map не изпълнява нищо, само създава структура.

1 2 3 4 5 6
let nums = &[1, 2, 3];

nums.iter().map(|&x| {
    println!("closure called");
    x * x
});
warning: unused `Map` that must be used --> src/bin/main_7fd5e64ecccba97f18fad915a941cf169b892ad4.rs:4:1 | 4 | / nums.iter().map(|&x| { 5 | | println!("closure called"); 6 | | x * x 7 | | }); | |__^ | = note: iterators are lazy and do nothing unless consumed = note: `#[warn(unused_must_use)]` on by default help: use `let _ = ...` to ignore the resulting value | 4 | let _ = nums.iter().map(|&x| { | +++++++
fn main() {
let nums = &[1, 2, 3];

nums.iter().map(|&x| {
    println!("closure called");
    x * x
});
}

Адаптери за итератори

map

Closure-а ще се извика чак когато започнем да обхождаме итератора

1 2 3 4 5 6 7 8 9 10
let nums = &[1, 2, 3];

let doubled = nums.iter().map(|&x| {
    println!("closure called");
    x * x
});

for num in doubled {
    println!("{}", num);
}
closure called 1 closure called 4 closure called 9
fn main() {
let nums = &[1, 2, 3];

let doubled = nums.iter().map(|&x| {
    println!("closure called");
    x * x
});

for num in doubled {
    println!("{}", num);
}
}

Адаптери за итератори

map

1 2 3 4 5 6 7 8 9 10 11 12 13 14
let iter1 = [1, 2, 3].iter();
let func = |&x| { x * x };

let iter2 = iter1.map(func);
for e in iter2 {
    code(e);
}

// работи все едно е написано

for e1 in iter1 {
    let e2 = func(e1);
    code(e2);
}
fn main() {
fn code(_x: i32) {}
let iter1 = [1, 2, 3].iter();
let func = |&x| { x * x };

{
let iter1 = iter1.clone();
let iter2 = iter1.map(func);
for e in iter2 {
    code(e);
}
}

// работи все едно е написано

{
for e1 in iter1 {
    let e2 = func(e1);
    code(e2);
}
}
}

Адаптери за итератори

map

1 2 3 4 5 6 7 8 9 10 11 12 13 14
let iter1 = [1, 2, 3].iter();
let func = |&x| { x * x };

let iter2 = iter1.map(func);
for e in iter2 {
    code(e);
}

// работи все едно е написано

for e1 in iter1 {
    let e2 = func(e1);
    code(e2);
}
fn main() {
fn code(_x: i32) {}
let iter1 = [1, 2, 3].iter();
let func = |&x| { x * x };

{
let iter1 = iter1.clone();
let iter2 = iter1.map(func);
for e in iter2 {
    code(e);
}
}

// работи все едно е написано

{
for e1 in iter1 {
    let e2 = func(e1);
    code(e2);
}
}
}

Адаптери за итератори

filter

1 2 3 4 5
let nums = &[1, 2, 3, 4, 5];

for e in nums.iter().filter(|&x| x % 2 != 0) {
    println!("{}", e);
}
1 3 5
fn main() {
let nums = &[1, 2, 3, 4, 5];

for e in nums.iter().filter(|&x| x % 2 != 0) {
    println!("{}", e);
}
}

Адаптери за итератори

map & filter

1 2 3 4 5 6 7 8 9
let nums = &[1, 2, 3, 4, 5];

for e in nums
    .iter()
    .filter(|&x| x % 2 != 0)
    .map(|&x| x * x)
{
    println!("{}", e);
}
1 9 25
fn main() {
let nums = &[1, 2, 3, 4, 5];

for e in nums
    .iter()
    .filter(|&x| x % 2 != 0)
    .map(|&x| x * x)
{
    println!("{}", e);
}
}

Адаптери за итератори

map & filter

1 2 3 4 5 6 7 8 9 10
let nums = &["12", "-23", "foo", "4", "bar"];

for e in nums
    .iter()
    .map(|s| s.parse::<i32>())
    .filter(|n| n.is_ok())
    .map(|n| n.unwrap())
{
    println!("{}", e);
}
12 -23 4
fn main() {
let nums = &["12", "-23", "foo", "4", "bar"];

for e in nums
    .iter()
    .map(|s| s.parse::())
    .filter(|n| n.is_ok())
    .map(|n| n.unwrap())
{
    println!("{}", e);
}
}

Адаптери за итератори

map & filter

1 2 3 4 5 6 7 8 9 10
let nums = &["12", "-23", "foo", "4", "bar"];

for e in nums
    .iter()                         // impl Iterator<Item = &str>
    .map(|s| s.parse::<i32>())      // impl Iterator<Item = Result<i32, ParseIntError>>
    .filter(|n| n.is_ok())          // impl Iterator<Item = Result<i32, ParseIntError>>
    .map(|n| n.unwrap())            // impl Iterator<Item = i32>
{
    println!("{}", e);
}
12 -23 4
fn main() {
let nums = &["12", "-23", "foo", "4", "bar"];

for e in nums
    .iter()                         // impl Iterator
    .map(|s| s.parse::())      // impl Iterator>
    .filter(|n| n.is_ok())          // impl Iterator>
    .map(|n| n.unwrap())            // impl Iterator
{
    println!("{}", e);
}
}

Адаптери за итератори

map & filter

1 2 3 4 5 6 7 8 9 10
let nums = &["12", "-23", "foo", "4", "bar"];

for e in nums
    .iter()                         // impl Iterator<Item = &str>
    .map(|s| s.parse::<i32>().ok()) // impl Iterator<Item = Option<i32>>
    .filter(|n| n.is_some())        // impl Iterator<Item = Option<i32>>
    .map(|n| n.unwrap())            // impl Iterator<Item = i32>
{
    println!("{}", e);
}
12 -23 4
fn main() {
let nums = &["12", "-23", "foo", "4", "bar"];

for e in nums
    .iter()                         // impl Iterator
    .map(|s| s.parse::().ok()) // impl Iterator>
    .filter(|n| n.is_some())        // impl Iterator>
    .map(|n| n.unwrap())            // impl Iterator
{
    println!("{}", e);
}
}

Адаптери за итератори

filter_map

1 2 3 4 5 6 7 8
let nums = &["12", "-23", "foo", "4", "bar"];

for e in nums
    .iter()                                 // impl Iterator<Item = &str>
    .filter_map(|s| s.parse::<i32>().ok())  // impl Iterator<Item = i32>
{
    println!("{}", e);
}
12 -23 4
fn main() {
let nums = &["12", "-23", "foo", "4", "bar"];

for e in nums
    .iter()                                 // impl Iterator
    .filter_map(|s| s.parse::().ok())  // impl Iterator
{
    println!("{}", e);
}
}

Адаптери за итератори

flatten

Ако имаме итератор, който връща итератори, flatten премахва едно ниво на вложеност

1 2 3 4 5 6 7 8 9 10 11 12
let capitals_map = BTreeMap::from([
    ('A', vec!["Athens", "Amsterdam"]),
    ('B', vec!["Brussels", "Berlin", "Budapest"]),
]);

for city in capitals_map
    .iter()                                 // impl Iterator<Item = (&char, &Vec<&str>)>
    .map(|(_, city_list)| city_list.iter()) // impl Iterator<Item = slice::Iter<&str>>
    .flatten()                              // impl Iterator<Item = &str>
{
    println!("{}", city);
}
Athens Amsterdam Brussels Berlin Budapest
use std::collections::BTreeMap;
fn main() {
let capitals_map = BTreeMap::from([
    ('A', vec!["Athens", "Amsterdam"]),
    ('B', vec!["Brussels", "Berlin", "Budapest"]),
]);

for city in capitals_map
    .iter()                                 // impl Iterator)>
    .map(|(_, city_list)| city_list.iter()) // impl Iterator>
    .flatten()                              // impl Iterator
{
    println!("{}", city);
}
}

Адаптери за итератори

flat_map

flat_map = map + flatten

1 2 3 4 5 6 7 8 9 10 11
let capitals_map = BTreeMap::from([
    ('A', vec!["Athens", "Amsterdam"]),
    ('B', vec!["Brussels", "Berlin", "Budapest"]),
]);

for city in capitals_map
    .iter()                                      // impl Iterator<Item = (&char, &Vec<&str>)>
    .flat_map(|(_, city_list)| city_list.iter()) // impl Iterator<Item = &str>
{
    println!("{}", city);
}
Athens Amsterdam Brussels Berlin Budapest
use std::collections::BTreeMap;
fn main() {
let capitals_map = BTreeMap::from([
    ('A', vec!["Athens", "Amsterdam"]),
    ('B', vec!["Brussels", "Berlin", "Budapest"]),
]);

for city in capitals_map
    .iter()                                      // impl Iterator)>
    .flat_map(|(_, city_list)| city_list.iter()) // impl Iterator
{
    println!("{}", city);
}
}

Адаптери за итератори

flat_map

flat_map приема и функции, които връщат I: IntoIterator

1 2 3 4 5 6 7 8 9 10 11
let capitals_map = BTreeMap::from([
    ('A', vec!["Athens", "Amsterdam"]),
    ('B', vec!["Brussels", "Berlin", "Budapest"]),
]);

for city in capitals_map
    .iter()                                      // impl Iterator<Item = (&char, &Vec<&str>)>
    .flat_map(|(_, city_list)| city_list)        // impl Iterator<Item = &str>
{
    println!("{}", city);
}
Athens Amsterdam Brussels Berlin Budapest
use std::collections::BTreeMap;
fn main() {
let capitals_map = BTreeMap::from([
    ('A', vec!["Athens", "Amsterdam"]),
    ('B', vec!["Brussels", "Berlin", "Budapest"]),
]);

for city in capitals_map
    .iter()                                      // impl Iterator)>
    .flat_map(|(_, city_list)| city_list)        // impl Iterator
{
    println!("{}", city);
}
}

Адаптери за итератори

take & skip

Адаптери за итератори

take & skip

Адаптери за итератори

take & skip

Адаптери за итератори

cloned & copied

Адаптери за итератори

cloned & copied

Адаптери за итератори

cloned & copied

Адаптери за итератори

cloned & copied

1 2 3 4 5
let nums = &[1, 2, 3, 4, 5];

let odd_nums = nums.iter()
    .filter(|&x| x % 2 != 0)
    .collect::<Vec<_>>();     // odd_nums: Vec<&i32>
fn main() {
let nums = &[1, 2, 3, 4, 5];

let odd_nums = nums.iter()
    .filter(|&x| x % 2 != 0)
    .collect::>();     // odd_nums: Vec<&i32>
}

Адаптери за итератори

cloned & copied

1 2 3 4 5
let nums = &[1, 2, 3, 4, 5];

let odd_nums = nums.iter()
    .filter(|&x| x % 2 != 0)
    .collect::<Vec<i32>>();
error[E0277]: a value of type `Vec<i32>` cannot be built from an iterator over elements of type `&{integer}` --> src/bin/main_3502f69e7ad063d5dac48e630b213049ead24a05.rs:6:16 | 6 | .collect::<Vec<i32>>(); | ------- ^^^^^^^^ value of type `Vec<i32>` cannot be built from `std::iter::Iterator<Item=&{integer}>` | | | required by a bound introduced by this call | = help: the trait `FromIterator<&{integer}>` is not implemented for `Vec<i32>` = help: the trait `FromIterator<i32>` is implemented for `Vec<i32>` = help: for that trait implementation, expected `i32`, found `&{integer}` note: the method call chain might not have had the expected associated types --> src/bin/main_3502f69e7ad063d5dac48e630b213049ead24a05.rs:4:21 | 2 | let nums = &[1, 2, 3, 4, 5]; | ---------------- this expression has type `&[{integer}; 5]` 3 | 4 | let odd_nums = nums.iter() | ^^^^^^ `Iterator::Item` is `&{integer}` here 5 | .filter(|&x| x % 2 != 0) | ----------------------- `Iterator::Item` remains `&{integer}` here note: required by a bound in `collect` --> /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/iter/traits/iterator.rs:1996:5 For more information about this error, try `rustc --explain E0277`. error: could not compile `rust` (bin "main_3502f69e7ad063d5dac48e630b213049ead24a05") due to 1 previous error
fn main() {
let nums = &[1, 2, 3, 4, 5];

let odd_nums = nums.iter()
    .filter(|&x| x % 2 != 0)
    .collect::>();
}

Адаптери за итератори

cloned & copied

1 2 3 4 5 6
let nums = &[1, 2, 3, 4, 5];

let odd_nums = nums.iter()
    .filter(|&x| x % 2 != 0)
    .copied()
    .collect::<Vec<i32>>();
fn main() {
let nums = &[1, 2, 3, 4, 5];

let odd_nums = nums.iter()
    .filter(|&x| x % 2 != 0)
    .copied()
    .collect::>();
}

Адаптери за итератори

zip

Обхожда два итератора едновременно

1 2 3 4 5 6
let values_a = &["foo", "bar", "baz"];
let values_b = &[1.2, 3.4, 5.6];

for (a, b) in values_a.iter().zip(values_b.iter()) {
    println!("{} => {}", a, b);
}
foo => 1.2 bar => 3.4 baz => 5.6
fn main() {
let values_a = &["foo", "bar", "baz"];
let values_b = &[1.2, 3.4, 5.6];

for (a, b) in values_a.iter().zip(values_b.iter()) {
    println!("{} => {}", a, b);
}
}

Адаптери за итератори

zip

Обхожда два итератора едновременно

1 2 3 4 5 6
let values_a = &["foo", "bar", "baz"];
let values_b = &[1.2, 3.4, 5.6];

for (a, b) in values_a.iter().zip(values_b) {
    println!("{} => {}", a, b);
}
foo => 1.2 bar => 3.4 baz => 5.6
fn main() {
let values_a = &["foo", "bar", "baz"];
let values_b = &[1.2, 3.4, 5.6];

for (a, b) in values_a.iter().zip(values_b) {
    println!("{} => {}", a, b);
}
}

Адаптери за итератори

zip

За повече симетричност има свободна функция std::iter::zip

1 2 3 4 5 6
let values_a = &["foo", "bar", "baz"];
let values_b = &[1.2, 3.4, 5.6];

for (a, b) in iter::zip(values_a, values_b) {
    println!("{} => {}", a, b);
}
foo => 1.2 bar => 3.4 baz => 5.6
fn main() {
use std::iter;
let values_a = &["foo", "bar", "baz"];
let values_b = &[1.2, 3.4, 5.6];

for (a, b) in iter::zip(values_a, values_b) {
    println!("{} => {}", a, b);
}
}

Адаптери за итератори

zip

1 2 3 4 5
let arr = &["foo", "bar", "baz"];

for (i, word) in (0..).zip(arr) {
    println!("arr[{}] = {}", i, word);
}
arr[0] = foo arr[1] = bar arr[2] = baz
fn main() {
let arr = &["foo", "bar", "baz"];

for (i, word) in (0..).zip(arr) {
    println!("arr[{}] = {}", i, word);
}
}

Адаптери за итератори

enumerate

1 2 3 4 5
let arr = &["foo", "bar", "baz"];

for (i, word) in arr.iter().enumerate() {
    println!("arr[{}] = {}", i, word);
}
arr[0] = foo arr[1] = bar arr[2] = baz
fn main() {
let arr = &["foo", "bar", "baz"];

for (i, word) in arr.iter().enumerate() {
    println!("arr[{}] = {}", i, word);
}
}

Функции върху итератори

други

Функции върху итератори

fold

1 2 3 4
let nums = &[1, 2, 3, 4, 5];

let sum = nums.iter().fold(0, |acc, x| acc + x);
println!("{}", sum);
15
fn main() {
let nums = &[1, 2, 3, 4, 5];

let sum = nums.iter().fold(0, |acc, x| acc + x);
println!("{}", sum);
}

Функции върху итератори

fold

1 2 3 4 5 6
let nums = &[1, 2, 3, 4, 5];

let expr = nums.iter().fold(String::from("X"), |acc, x| {
    format!("({acc} + {x})")
});
println!("{}", expr);
(((((X + 1) + 2) + 3) + 4) + 5)
fn main() {
let nums = &[1, 2, 3, 4, 5];

let expr = nums.iter().fold(String::from("X"), |acc, x| {
    format!("({acc} + {x})")
});
println!("{}", expr);
}

Функции върху итератори

fold

Други подобни:

1 2 3 4
let nums = &[1, 2, 3, 4, 5];

let sum = nums.iter().sum::<i32>();
println!("{}", sum);
15
fn main() {
let nums = &[1, 2, 3, 4, 5];

let sum = nums.iter().sum::();
println!("{}", sum);
}

Функции върху итератори

collect

1 2 3 4
let arr = &[1, 2, 3];

let vec = arr.iter().copied().collect::<Vec<_>>();
println!("{:?}", vec);
[1, 2, 3]
fn main() {
let arr = &[1, 2, 3];

let vec = arr.iter().copied().collect::>();
println!("{:?}", vec);
}

Collect

Типа на резултата трябва да имплементира FromIterator

1 2 3 4 5 6 7 8 9 10 11 12 13 14
pub trait Iterator {
    /* ... */

    fn collect<B>(self) -> B
    where
        B: FromIterator<Self::Item>,
        Self: Sized,
    { /* ... */ }
}

pub trait FromIterator<T>: Sized {
    fn from_iter<I>(iter: I) -> Self
       where I: IntoIterator<Item = T>;
}

Collect

Типа на резултата трябва да имплементира FromIterator

1 2 3 4 5 6 7 8 9 10 11 12 13 14
pub trait Iterator {
    /* ... */

    fn collect<B>(self) -> B
    where
        B: FromIterator<Self::Item>,
        Self: Sized,
    { /* ... */ }
}

pub trait FromIterator<T>: Sized {
    fn from_iter<I>(iter: I) -> Self
       where I: IntoIterator<Item = T>;
}

Collect

Някои полезни имплементации:

1 2 3 4 5 6 7
// Iterator<Item = T> => Vec<T>

let v: Vec<_> = vec![1, 2, 3]
    .into_iter()
    .collect();

println!("{:?}", v);
[1, 2, 3]
fn main() {
// Iterator => Vec

let v: Vec<_> = vec![1, 2, 3]
    .into_iter()
    .collect();

println!("{:?}", v);
}
1 2 3 4 5 6 7
// Iterator<Item = char> => String

let s: String = vec!['a', 'b', 'c']
    .into_iter()
    .collect();

println!("{:?}", s);
"abc"
fn main() {
// Iterator => String

let s: String = vec!['a', 'b', 'c']
    .into_iter()
    .collect();

println!("{:?}", s);
}

Collect

Някои полезни имплементации:

1 2 3 4 5 6 7 8 9 10
// Iterator<Item = (K, V)> => HashMap<K, V>

let map: HashMap<_, _> = vec![
        (String::from("foo"), 1),
        (String::from("bar"), 2),
    ]
    .into_iter()
    .collect();

println!("{:?}", map);
{"foo": 1, "bar": 2}
use std::collections::HashMap;
fn main() {
// Iterator => HashMap

let map: HashMap<_, _> = vec![
        (String::from("foo"), 1),
        (String::from("bar"), 2),
    ]
    .into_iter()
    .collect();

println!("{:?}", map);
}

Collect

Някои полезни имплементации:

1 2 3 4 5 6 7
// Iterator<Item = Result<T, E>> => Result<Vec<T>, E>

let res: Result<Vec<_>, &str> = vec![Ok(1), Ok(2), Ok(3)]
    .into_iter()
    .collect();

println!("{:?}", res);
Ok([1, 2, 3])
fn main() {
// Iterator> => Result, E>

let res: Result, &str> = vec![Ok(1), Ok(2), Ok(3)]
    .into_iter()
    .collect();

println!("{:?}", res);
}
1 2 3 4 5 6 7
// Iterator<Item = Result<T, E>> => Result<Vec<T>, E>

let res: Result<Vec<_>, _> = vec![Ok(1), Err("not two"), Ok(3)]
    .into_iter()
    .collect();

println!("{:?}", res);
Err("not two")
fn main() {
// Iterator> => Result, E>

let res: Result, _> = vec![Ok(1), Err("not two"), Ok(3)]
    .into_iter()
    .collect();

println!("{:?}", res);
}

Функции върху итератори

Itertools

Itertools

Примери

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
struct Grid {
    /* ... */
}

impl Grid {
    /// Get the cells that are neighbours to the cell at coords (x, y)
    fn neighbours(&self, x: i32, y: i32) -> impl Iterator<Item = &Cell> {
        let coords = &[(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)];

        coords.iter()
            .copied()
            .map(|(offset_x, offset_y)| (x + offset_x, y + offset_y))
            .filter(|&coord| self.is_inside(coord))
            .map(|coord| self.cell_at(coord))
    }
}

Примери

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
struct Grid {
    /* ... */
}

impl Grid {
    /// Get the cells that are neighbours to the cell at coords (x, y)
    fn neighbours(&self, x: i32, y: i32) -> impl Iterator<Item = &Cell> {
        let coords = &[(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)];

        coords.iter()
            .copied()
            .map(|(offset_x, offset_y)| (x + offset_x, y + offset_y))
            .filter(|&coord| self.is_inside(coord))
            .map(|coord| self.cell_at(coord))
    }
}
error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function --> src/bin/main_9e52df91a70bfadd6a04bbb6f30949788707bba3.rs:14:18 | 14 | .map(|(offset_x, offset_y)| (x + offset_x, y + offset_y)) | ^^^^^^^^^^^^^^^^^^^^^^ - `x` is borrowed here | | | may outlive borrowed value `x` | note: closure is returned here --> src/bin/main_9e52df91a70bfadd6a04bbb6f30949788707bba3.rs:12:9 | 12 | / coords.iter() 13 | | .copied() 14 | | .map(|(offset_x, offset_y)| (x + offset_x, y + offset_y)) 15 | | .filter(|&coord| self.is_inside(coord)) 16 | | .map(|coord| self.cell_at(coord)) | |_____________________________________________^ help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword | 14 | .map(move |(offset_x, offset_y)| (x + offset_x, y + offset_y)) | ++++ error[E0373]: closure may outlive the current function, but it borrows `y`, which is owned by the current function --> src/bin/main_9e52df91a70bfadd6a04bbb6f30949788707bba3.rs:14:18 | 14 | .map(|(offset_x, offset_y)| (x + offset_x, y + offset_y)) | ^^^^^^^^^^^^^^^^^^^^^^ - `y` is borrowed here | | | may outlive borrowed value `y` | note: closure is returned here --> src/bin/main_9e52df91a70bfadd6a04bbb6f30949788707bba3.rs:12:9 | 12 | / coords.iter() 13 | | .copied() 14 | | .map(|(offset_x, offset_y)| (x + offset_x, y + offset_y)) 15 | | .filter(|&coord| self.is_inside(coord)) 16 | | .map(|coord| self.cell_at(coord)) | |_____________________________________________^ help: to force the closure to take ownership of `y` (and any other referenced variables), use the `move` keyword | 14 | .map(move |(offset_x, offset_y)| (x + offset_x, y + offset_y)) | ++++ error[E0373]: closure may outlive the current function, but it borrows `self`, which is owned by the current function --> src/bin/main_9e52df91a70bfadd6a04bbb6f30949788707bba3.rs:15:21 | 15 | .filter(|&coord| self.is_inside(coord)) | ^^^^^^^^ ---- `self` is borrowed here | | | may outlive borrowed value `self` | note: closure is returned here --> src/bin/main_9e52df91a70bfadd6a04bbb6f30949788707bba3.rs:12:9 | 12 | / coords.iter() 13 | | .copied() 14 | | .map(|(offset_x, offset_y)| (x + offset_x, y + offset_y)) 15 | | .filter(|&coord| self.is_inside(coord)) 16 | | .map(|coord| self.cell_at(coord)) | |_____________________________________________^ help: to force the closure to take ownership of `self` (and any other referenced variables), use the `move` keyword | 15 | .filter(move |&coord| self.is_inside(coord)) | ++++ error[E0373]: closure may outlive the current function, but it borrows `self`, which is owned by the current function --> src/bin/main_9e52df91a70bfadd6a04bbb6f30949788707bba3.rs:16:18 | 16 | .map(|coord| self.cell_at(coord)) | ^^^^^^^ ---- `self` is borrowed here | | | may outlive borrowed value `self` | note: closure is returned here --> src/bin/main_9e52df91a70bfadd6a04bbb6f30949788707bba3.rs:12:9 | 12 | / coords.iter() 13 | | .copied() 14 | | .map(|(offset_x, offset_y)| (x + offset_x, y + offset_y)) 15 | | .filter(|&coord| self.is_inside(coord)) 16 | | .map(|coord| self.cell_at(coord)) | |_____________________________________________^ help: to force the closure to take ownership of `self` (and any other referenced variables), use the `move` keyword | 16 | .map(move |coord| self.cell_at(coord)) | ++++ For more information about this error, try `rustc --explain E0373`. error: could not compile `rust` (bin "main_9e52df91a70bfadd6a04bbb6f30949788707bba3") due to 4 previous errors
fn main() {}
struct Cell {}
struct Grid {
    /* ... */
}

impl Grid {
    /// Get the cells that are neighbours to the cell at coords (x, y)
    fn neighbours(&self, x: i32, y: i32) -> impl Iterator {
        let coords = &[(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)];

        coords.iter()
            .copied()
            .map(|(offset_x, offset_y)| (x + offset_x, y + offset_y))
            .filter(|&coord| self.is_inside(coord))
            .map(|coord| self.cell_at(coord))
    }
fn is_inside(&self, coord: (i32, i32)) -> bool { true }
fn cell_at(&self, coord: (i32, i32)) -> &Cell { todo!() }
}

Примери

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
struct Grid {
    /* ... */
}

impl Grid {
    /// Get the cells that are neighbours to the cell at coords (x, y)
    fn neighbours(&self, x: i32, y: i32) -> impl Iterator<Item = &Cell> {
        let coords = &[(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)];

        coords.iter()
            .copied()
            .map(move |(offset_x, offset_y)| (x + offset_x, y + offset_y))
            .filter(|&coord| self.is_inside(coord))
            .map(|coord| self.cell_at(coord))
    }
}
error[E0373]: closure may outlive the current function, but it borrows `self`, which is owned by the current function --> src/bin/main_d8cfe8fdb3c4b57c61c19f39e5d4a446428264ab.rs:15:21 | 15 | .filter(|&coord| self.is_inside(coord)) | ^^^^^^^^ ---- `self` is borrowed here | | | may outlive borrowed value `self` | note: closure is returned here --> src/bin/main_d8cfe8fdb3c4b57c61c19f39e5d4a446428264ab.rs:12:9 | 12 | / coords.iter() 13 | | .copied() 14 | | .map(move |(offset_x, offset_y)| (x + offset_x, y + offset_y)) 15 | | .filter(|&coord| self.is_inside(coord)) 16 | | .map(|coord| self.cell_at(coord)) | |_____________________________________________^ help: to force the closure to take ownership of `self` (and any other referenced variables), use the `move` keyword | 15 | .filter(move |&coord| self.is_inside(coord)) | ++++ error[E0373]: closure may outlive the current function, but it borrows `self`, which is owned by the current function --> src/bin/main_d8cfe8fdb3c4b57c61c19f39e5d4a446428264ab.rs:16:18 | 16 | .map(|coord| self.cell_at(coord)) | ^^^^^^^ ---- `self` is borrowed here | | | may outlive borrowed value `self` | note: closure is returned here --> src/bin/main_d8cfe8fdb3c4b57c61c19f39e5d4a446428264ab.rs:12:9 | 12 | / coords.iter() 13 | | .copied() 14 | | .map(move |(offset_x, offset_y)| (x + offset_x, y + offset_y)) 15 | | .filter(|&coord| self.is_inside(coord)) 16 | | .map(|coord| self.cell_at(coord)) | |_____________________________________________^ help: to force the closure to take ownership of `self` (and any other referenced variables), use the `move` keyword | 16 | .map(move |coord| self.cell_at(coord)) | ++++ For more information about this error, try `rustc --explain E0373`. error: could not compile `rust` (bin "main_d8cfe8fdb3c4b57c61c19f39e5d4a446428264ab") due to 2 previous errors
fn main() {}
struct Cell {}
struct Grid {
    /* ... */
}

impl Grid {
    /// Get the cells that are neighbours to the cell at coords (x, y)
    fn neighbours(&self, x: i32, y: i32) -> impl Iterator {
        let coords = &[(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)];

        coords.iter()
            .copied()
            .map(move |(offset_x, offset_y)| (x + offset_x, y + offset_y))
            .filter(|&coord| self.is_inside(coord))
            .map(|coord| self.cell_at(coord))
    }
fn is_inside(&self, coord: (i32, i32)) -> bool { true }
fn cell_at(&self, coord: (i32, i32)) -> &Cell { todo!() }
}

Примери

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
struct Grid {
    /* ... */
}

impl Grid {
    /// Get the cells that are neighbours to the cell at coords (x, y)
    fn neighbours(&self, x: i32, y: i32) -> impl Iterator<Item = &Cell> {
        let coords = &[(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)];

        coords.iter()
            .copied()
            .map(move |(offset_x, offset_y)| (x + offset_x, y + offset_y))
            .filter(move |&coord| self.is_inside(coord))
            .map(move |coord| self.cell_at(coord))
    }
}
fn main() {}
struct Cell {}
struct Grid {
    /* ... */
}

impl Grid {
    /// Get the cells that are neighbours to the cell at coords (x, y)
    fn neighbours(&self, x: i32, y: i32) -> impl Iterator {
        let coords = &[(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)];

        coords.iter()
            .copied()
            .map(move |(offset_x, offset_y)| (x + offset_x, y + offset_y))
            .filter(move |&coord| self.is_inside(coord))
            .map(move |coord| self.cell_at(coord))
    }
fn is_inside(&self, coord: (i32, i32)) -> bool { true }
fn cell_at(&self, coord: (i32, i32)) -> &Cell { todo!() }
}

Въпроси