Работа с итератори
12 ноември 2024
Административни неща
- първо предизвикателство - https://fmi.rust-lang.bg/challenges/1
Преговор
- често срещани типажи
- Copy, Clone, Drop, Debug, Default, Hash
- могат да се
#[derive]
-нат
- предефиниране на оператори
- PartialEq, Eq, ParitialOrd, Ord
- анонимни функции (closures), как се имплементират
- типажи Fn, FnMut, FnOnce
- приемане като аргумент
- връщане като резултат
Итератори
pub trait Iterator {
type Item;
// Required method
fn next(&mut self) -> Option<Self::Item>;
// Provided methods
// ...75 methods
}
Итератори
- итераторите може да са крайни
- итериране по колекция
for word in &["foo", "bar", "baz"] {
println!("{}", word);
}
foo bar baz
fn main() { for word in &["foo", "bar", "baz"] { println!("{}", word); } }
Итератори
- итераторите може да са безкрайни
- поток от стойности
for n in 1.. {
println!("{n} mississippi");
}
fn main() { for n in 1.. { println!("{n} mississippi"); } }
Разгъване на for-цикъл
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
Указва, че даден тип може да се конвертира до итератор
pub trait IntoIterator {
type Item;
type IntoIter: Iterator<Item = Self::Item>;
fn into_iter(self) -> Self::IntoIter;
}
trait IntoIterator
Вектора може да се превърне в итератор.
Това консумира вектора - итератора връща един по един елементите по стойност
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()
for val in vec {
}
for val in vec.into_iter() {
}
trait IntoIterator
Еквивалентно е дали ще итерираме по vec
или vec.into_iter()
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
impl<I: Iterator> IntoIterator for I {
type Item = I::Item;
type IntoIter = I;
fn into_iter(self) -> I {
self
}
}
trait IntoIterator
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()
for val in &vec {
}
for val in vec.iter() {
}
IntoIterator за референции
- трябва ли ни отделен trait за това?
RefIntoIterator
??RefMutIntoIterator
??
IntoIterator за референции
Не, защото има отделна имплементация на IntoIterator
за референция към вектор
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 референция към вектор
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 за референции
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()
.
Е въпрос на лична преференция.
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() { /* ... */ }
Адаптери за итератори
Адаптери за итератори
Iterator
trait-а изисква да имплементираме една единствена функция -next
.
Адаптери за итератори
Iterator
trait-а изисква да имплементираме една единствена функция -next
.- но предоставя голямо количество функции наготово
Адаптери за итератори
Iterator
trait-а изисква да имплементираме една единствена функция -next
.- но предоставя голямо количество функции наготово
- повечето са адаптери - консумират итератора и връщат нов итератор, който връща променен поток от елементи
Адаптери за итератори
map
Трансформира всяка стойност от итератора, използвайки функция T -> U
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
, която си запазва оригиналния итератор и функцията.
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
, която си запазва оригиналния итератор и функцията.
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
не изпълнява нищо, само създава структура.
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-а ще се извика чак когато започнем да обхождаме итератора
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
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
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); } } }
- при компилиране с оптимизации междинните структури могат да се премахнат и извикванията на функции да се inline-нат
- често генерираното assembly за код с итератори и код с цикли е едно и също
Адаптери за итератори
filter
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
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
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
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
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
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); } }
filter_map
приема функцияT -> Option<U>
- комбинира
map
+filter
Адаптери за итератори
flatten
Ако имаме итератор, който връща итератори, flatten
премахва едно ниво на вложеност
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
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
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(n)
- връща първите N елемента от итератора, след товаNone
skip(n)
- пропуска първите N елемента от итератора
Адаптери за итератори
take & skip
take(n)
- връща първите N елемента от итератора, след товаNone
skip(n)
- пропуска първите N елемента от итератораtake_while(fn)
- връща елементи, докато подадената функция връща trueskip_while(fn)
- пропуска елементи, докато подадената функция връща true
Адаптери за итератори
take & skip
take(n)
- връща първите N елемента от итератора, след товаNone
skip(n)
- пропуска първите N елемента от итератораtake_while(fn)
- връща елементи, докато подадената функция връща trueskip_while(fn)
- пропуска елементи, докато подадената функция връща true- полезни при безкрайни итератори
Адаптери за итератори
cloned & copied
Iterator<Item = &T>
->Iterator<Item = T>
Адаптери за итератори
cloned & copied
Iterator<Item = &T>
->Iterator<Item = T>
iter.cloned()
=iter.map(|x| x.clone())
iter.copied()
=iter.map(|&x| x)
, но трябваT: Copy
Адаптери за итератори
cloned & copied
Iterator<Item = &T>
->Iterator<Item = T>
iter.cloned()
=iter.map(|x| x.clone())
iter.copied()
=iter.map(|&x| x)
, но трябваT: Copy
- основно се ползват с итератори по примитивни типове
- имаме итератор по
&число
, трябва ни итератор почисло
Адаптери за итератори
cloned & copied
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
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
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
Обхожда два итератора едновременно
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
Обхожда два итератора едновременно
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
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
- ако двата итератора имат различна дължина - спира, като се изчерпи по-краткия
- можем да комбинираме с безкраен интервал, за да итерираме по елемент с индекс
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
- това се използва често
- затова има отделна функция -
enumerate
- която прави същото
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); } }
Функции върху итератори
други
find(pred)
- връщаSome(elem)
с първия елемент, който отговаря на предиката, илиNone
all(pred)
- връщаtrue
ако всички елементи отговарят на предиката, иначеfalse
any(pred)
- връщаtrue
ако съществува елемент, отговарящ на предиката, иначеfalse
Функции върху итератори
fold
fold(init, fn)
- събира всички елементи на итератора в една стойност, използвайки подадената функция- приема функция
(B, T) -> B
- първият аргумент е акумулираната стойност до момента
- вторият аргумент е елемент от итератора
- операцията също се нарича reduce или accumulate
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
- още един пример
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
Други подобни:
sum
- fold, използвайки оператор+
product
- fold, използвайки оператор*
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
collect
- fold, който събира елементите в дадена колекция
- generic по типа на резултата
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
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
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>;
}
- подобно на
str::parse
иFromStr
Collect
Някои полезни имплементации:
// 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); }
// 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
Някои полезни имплементации:
// 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
Някои полезни имплементации:
// 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); }
// 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); }
Функции върху итератори
- и други
- разгледайте си документацията на Iterator
Itertools
- ако функциите в std не са ви достатъчни
- https://docs.rs/itertools/
- Extra iterator adaptors, functions and macros.
Itertools
join
- Combine all iterator elements into oneString
, separated bysep
.multizip
- An iterator that generalizes.zip()
and allows running multiple iterators in lockstep.cons_tuples
- Create an iterator that maps for example iterators of((A, B), C)
to(A, B, C)
.- …
Примери
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))
}
}
Примери
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!() } }
Примери
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!() } }
Примери
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!() } }