应对延迟迭代器

and*_*y g 2 iterator lazy-evaluation rust

我正在尝试使用map()over迭代器对数组进行排序.

struct A {
    b: Vec<B>,
}

#[derive(PartialEq, Eq, PartialOrd, Ord)]
struct B {
    c: Vec<i32>,
}

fn main() {
    let mut a = A { b: Vec::new() };

    let b = B { c: vec![5, 2, 3] };
    a.b.push(b);

    a.b.iter_mut().map(|b| b.c.sort());
}
Run Code Online (Sandbox Code Playgroud)

发出警告:

warning: unused `std::iter::Map` that must be used
  --> src/main.rs:16:5
   |
16 |     a.b.iter_mut().map(|b| b.c.sort());
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: #[warn(unused_must_use)] on by default
   = note: iterators are lazy and do nothing unless consumed
Run Code Online (Sandbox Code Playgroud)

这是真的,sort()实际上并没有在这里调用.书中描述了这个警告,但我真的不明白为什么它会以这种方式工作iter_mut()以及为什么这种变化可以正常工作:

a.b.iter_mut().find(|b| b == b).map(|b| b.c.sort());
Run Code Online (Sandbox Code Playgroud)

jki*_*ski 7

正如你所链接的那本书所说:"如果你试图在迭代器上执行闭包以获得副作用,那就for改用它."

这样它的工作原理,任何阅读代码的人都会更清楚.您map希望将矢量"转换"为另一个矢量时使用.

  • 当您有一个向量并且希望其内容采用不同的格式而不修改原始向量时,将使用Map.如果要破坏性地修改向量,则应使用循环. (3认同)

shy*_*an1 6

我用for_each。根据文档:

它等效于for在迭代器上使用循环,尽管breakcontinue不可能从闭包中实现。使用循环通常更惯用for,但for_each在处理较长迭代器链末尾的项时可能更清晰。在某些情况下for_each也可能比循环更快,因为它将在适配器上使用内部迭代,例如Chain.


Pet*_*all 5

我不明白为什么这种变化iter_mut()效果很好:

a.b.iter_mut().find(|b| b == b).map(|b| b.c.sort());
Run Code Online (Sandbox Code Playgroud)

它有效,因为find它不懒惰;它是一个迭代器消费者。它返回一个Optionnot an Iterator。这可能就是它让您感到困惑的原因,因为Option还有一种map方法,这就是您在这里使用的方法。


正如其他人所说,map旨在转换数据,而不修改它并且没有任何其他副作用。如果您真的想使用map,您可以映射集合并将其分配回:

fn main() {
    let mut a = A { b: Vec::new() };
    let mut b = B { c: vec![5, 2, 3] };
    a.b.push(b);

    a.b =
        a.b.into_iter()
            .map(|mut b| {
                b.c.sort();
                b
            })
            .collect();
}
Run Code Online (Sandbox Code Playgroud)

请注意,vector 的sort方法返回(),因此您必须从映射函数中显式返回已排序的向量。