Rust 如何避免此程序的for循环和let语句

Rust 如何避免此程序的for循环和let语句,rust,Rust,在Rust中,如何避免编写循环和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;

在Rust中,如何避免编写循环和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
}
pub结构{
x:使用,
y:使用,
}
pub fn foo(文本:&str,字符串:&str)->Vec{
让mut r=Vec::new();
设mut x=0;
用于文本中的行。行(){
对于行中的(y,u)。匹配索引(字符串){
r、 推(左){
x:x,
y:y,})
}
x+=1;
}
R
}

以下是您提供的转换为使用迭代器的代码:

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()
}
pub fn foo(文本:&str,字符串:&str)->Vec{
文本
.行()
//允许我们在迭代期间获取当前计数*和*元素
.enumerate()
//将内部迭代器展平为一个迭代器
.平面图(|(索引,线)|{
线
.match_索引(字符串)
//内部迭代器
.map(移动|(y,|)L{x:index,y:y})
})
//将迭代器收集到'L'的'Vec'中`
收集::()
}

这是使用迭代器的等效方法:

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()
}
用于将
T
的迭代器转换为
(usize,T)
的迭代器,基本上使用索引压缩原始值。这样做是因为您使用
x
跟踪行号

.flat_map(|(x, line)| { ... })
用于允许迭代器中的每个值返回自己的迭代器,然后将迭代器的值展平为一个流

line.match_indices(string).map(move |(y, _)| { L { x, y } })
这里我们只是使用
x
y
创建一个
L
<之所以使用code>move,是因为在其他情况下,
x
将被借用用于闭包,但迭代器和闭包将返回到
flat\u map
闭包,寿命长于
x
move
只是复制
x
,所以这不是问题

.collect()
用于将迭代器转换为可以从迭代器生成的内容,方法是实现
fromterator
,通常是
Vec
等集合。这也是使用类型推断,因为我们知道返回的是
Vec
,它知道收集到
Vec


您可以在上验证等效性。

可以这样尝试:

#[派生(调试)]
公共结构{
x:使用,
y:使用,
}
pub fn foo(文本:&str,字符串:&str)->Vec{
text.lines()
.enumerate()
.地图(|(x,线)|
行。匹配索引(字符串)
.map(移动|(y,| L{x,y}))
.flatte()
.collect()
}
fn main(){
println!(“{:?}”,foo(
“aaa bbb ccc\nbbb aaa ccc\nccc aaa bbb”,
“bbb”))
//[L{x:0,y:4},L{x:1,y:0},L{x:2,y:8}]
}

好吧,我用同样的代码和像样的解释比你领先了5分钟……)很高兴被其他答案验证。:)虽然我并不惊讶;这些迭代器模式和解决方案甚至在语言上已经相当规范化了(有些只是使用不同的术语)。在修改它之前,使用迭代器链,考虑这是否是一个改进(除非这只是一个心理练习,在这种情况下,发疯)。循环中没有索引来删除不必要的边界检查,不可能预先分配具有正确大小的向量,并且嵌套的
for
循环可读性很好。我可以看到这一点,所以如果你觉得命令式版本更容易理解,不要觉得你必须改变它。有些人过分追求一切功能,忘记了生锈在内心是必不可少的;-)@特伦特:我完全同意。也就是说,我至少要添加
enumerate()
调用,以避免可变
x
和增量:这对我来说是绝对的收益。
平面地图
。。。嗯,好吧,说得好
enumerate()
是赢家,我同意。