将迭代器链接在一起以删除重复的代码



下面的代码尝试将两个迭代器链接在一起。

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另一个是RangeMap

解决方案是使用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);
}
}

这使得verticalhorizontal迭代器具有相同的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(())
}

最新更新