在 Rust 中,如何避免编写 for 循环和 let 语句?该程序用于记录字符串出现在文本的哪一行以及出现在该行的位置。
我知道我可以使用迭代器和映射来消除它们,但是我刚刚接触了 Rust,我不知道如何编写它。
pub struct L{
x: usize,
y: usize,
}
pub fn foo (text: &str, string: &str)->Vec<L> {
let mut r= Vec::new();
let mut x=0;
for line in text.lines(){
for (y, _) in line.match_indices(string){
r.push(L{
x : x,
y: y, })
}
x+=1;
}
r
}
Run Code Online (Sandbox Code Playgroud)
这是等效的使用迭代器:
pub fn foo(text: &str, string: &str) -> Vec<L> {
text.lines()
.enumerate()
.flat_map(|(x, line)| {
line.match_indices(string).map(move |(y, _)| { L { x, y } })
})
.collect()
}
Run Code Online (Sandbox Code Playgroud)
线的分解线:
.enumerate()
Run Code Online (Sandbox Code Playgroud)
enumerate用于将 的迭代器T转换为 的迭代器(usize, T),基本上是用索引压缩原始值。您这样做是因为您正在使用 跟踪行号x。
.flat_map(|(x, line)| { ... })
Run Code Online (Sandbox Code Playgroud)
flat_map 用于允许迭代器中的每个值返回其自己的迭代器,然后将其值展平为一个流。
line.match_indices(string).map(move |(y, _)| { L { x, y } })
Run Code Online (Sandbox Code Playgroud)
这里我们只是使用map采取x和y创造的L。move被使用是因为否则x会为闭包借用,但迭代器和闭包返回给flat_map闭包,存活时间比x. 这move只是复制,x所以这不是问题。
.collect()
Run Code Online (Sandbox Code Playgroud)
collect用于将迭代器转换为可以通过实现从迭代器生成的东西FromIterator,通常是像Vec. 这也是通过知道我们正在返回 a 来使用类型推断Vec<L>,它知道收集到 a 中Vec<L>。
您可以在 上验证等效性Rust Playground。