下面的代码尝试将两个迭代器链接在一起。
fn main() {
let height = 3;
let width = 4;
let horizontal = (0..height).map(|row| {let rw = row * width; rw..rw + width});
horizontal.for_each(|x| { print!("("); x.for_each(|x|print!(" {:?} ", x)); println!(")");});
let vertical = (0..width).map(|col| (0..height).map(move |n| col + n * width));
vertical.for_each(|x| { print!("("); x.for_each(|x|print!(" {:?} ", x)); println!(")");});
let all = horizontal.chain(vertical);
//all.for_each(|x| { print!("("); x.for_each(|x|print!(" {:?} ", x)); println!(")");});
}
但是编译器抱怨类型不匹配。
error[E0271]: type mismatch resolving `<Map<std::ops::Range<{integer}>, [closure@src/main.rs:6:35: 6:82]> as IntoIterator>::Item == std::ops::Range<{integer}>`
--> src/main.rs:8:26
|
8 | let all = horizontal.chain(vertical);
| ^^^^^ expected struct `Map`, found struct `std::ops::Range`
|
= note: expected type `Map<std::ops::Range<{integer}>, [closure@src/main.rs:6:57: 6:81]>`
found struct `std::ops::Range<{integer}>`
链的签名是:
fn chain<U>(self, other: U) -> Chain<Self, <U as IntoIterator>::IntoIter>ⓘ where
U: IntoIterator<Item = Self::Item>
两个迭代器都具有具有相同 Item 类型的迭代器作为 Item 类型,诚然,这并不完全符合签名的要求。但是我可以在每个迭代器上调用例如.for_each(|x| { print!("("); x.for_each(|x|print!(" {:?} ", x)); println!(")");})
,那么为什么我不能构建链来在链上调用它呢?有没有另一种方法可以消除这种代码重复?
这是因为您的类型没有相同的Item
:
.map(|row| {let rw = row * width; rw..rw + width});
.map(|col| (0..height).map(move |n| col + n * width))
一个是Range
另一个是Range
的Map
。
解决方案是使用flatten()
或根据您的情况flat_map()
:
fn main() {
let height = 3;
let width = 4;
println!("Horizontal:");
let horizontal = (0..height).flat_map(|row| {
let rw = row * width;
rw..rw + width
});
for x in horizontal.clone() {
println!("{:?}", x);
}
println!("nVertical:");
let vertical = (0..width).flat_map(|col| (0..height).map(move |n| col + n * width));
for x in vertical.clone() {
println!("{:?}", x);
}
println!("nAll:");
let all = horizontal.chain(vertical);
for x in all {
println!("{:?}", x);
}
}
这使得vertical
和horizontal
迭代器具有相同的Item
类型。此外,我删除了for_each()
在我看来,它使代码不清楚,因为循环是出于副作用,这是命令式范式,迭代器链接是功能范式。
奖金:
fn print_my_iter(name: &str, iter: impl Iterator<Item = i32>) {
println!("{}:", name);
for x in iter {
println!("{:?}", x);
}
}
fn main() {
let height = 3;
let width = 4;
let horizontal = (0..height).flat_map(|row| {
let rw = row * width;
rw..rw + width
});
print_my_iter("Horizontal", horizontal.clone());
let vertical = (0..width).flat_map(|col| (0..height).map(move |n| col + n * width));
print_my_iter("nVertical", vertical.clone());
let all = horizontal.chain(vertical);
print_my_iter("nAll", all);
}
<小时 />超级加成:
use std::io::{self, Write};
fn print_my_iter(name: &str, iter: impl Iterator<Item = i32>) -> Result<(), io::Error> {
let stdout = io::stdout();
let mut handle = stdout.lock();
writeln!(handle, "{}:", name)?;
iter.map(|x| writeln!(handle, "{:?}", x)).collect()
}
fn main() -> Result<(), io::Error> {
let height = 3;
let width = 4;
let horizontal = (0..height).flat_map(|row| {
let rw = row * width;
rw..rw + width
});
print_my_iter("Horizontal", horizontal.clone())?;
let vertical = (0..width).flat_map(|col| (0..height).map(move |n| col + n * width));
print_my_iter("nVertical", vertical.clone())?;
let all = horizontal.chain(vertical);
print_my_iter("nAll", all)?;
Ok(())
}