为什么Iterator::all需要迭代器可变?

3
我正在使用一个迭代器来遍历一个字符串的字符:
pub fn is_yelling(message: &str) -> bool {
    let letters = message.chars().filter(|c| c.is_alphabetic());
    message.chars().any(|c| c.is_alphabetic()) && letters.all(|c| c.is_uppercase())
}

这会引发编译错误:
error[E0596]: cannot borrow immutable local variable `letters` as mutable
 --> src/main.rs:3:51
  |
2 |     let letters = message.chars().filter(|c| c.is_alphabetic());
  |         ------- consider changing this to `mut letters`
3 |     message.chars().any(|c| c.is_alphabetic()) && letters.all(|c| c.is_uppercase())
  |                                                   ^^^^^^^ cannot borrow mutably

当我将letters设置为可变时,一切都顺利进行。

我不明白为什么这是必要的。 all方法不应该改变迭代器。就像mapfilter一样,它们将self而不是mut self作为参数。

我的有关map / filter / all的参考资料

我看到了有关此问题的问题,但没有解释。

2个回答

9
迭代任何内容都需要改变迭代器,因为Iterator::next需要使用&mut self。检查迭代器中的所有值都需要迭代,因此Iterator::all(和许多类似的方法)也需要使用&mut self

all方法不应该改变迭代器。

我非常想知道您是如何在不调用next的情况下检查迭代器中的每个值。

就像mapfilter一样

这些方法返回一个新的迭代器,它们不会调用next。尽管如此,如果需要,它们仍然可以调用next,因为...

它们使用self而不是mut self作为参数。

可变性是变量所有者的属性。这两个函数是等价的:

fn example(mut a: String) {}

fn example(a: String) {
    let mut a = a;
}

重要的是,在生成的文档中,两者看起来都一样 —— 签名中都没有 mut。这是因为对调用方来说没有关系。


好的,谢谢你的解释。我怀疑它与Iterator::next的调用有关,但是对于map/filter的情况无法理解。 - Justmaker

5
迭代器方法 allany 需要可变引用,因为它们将通过消耗其元素来修改迭代器(注意,next() 也需要 &mut self,因为它本质上修改了迭代器的状态)。此外,这些方法是短路求值的,不一定会消费迭代器的所有元素。这意味着这些方法可以将迭代器返回给调用者,从而能够在需要时继续消费迭代器。
let x = vec![1, 2, 5];
let mut it = x.into_iter();
assert!(it.any(|x| x > 1));
assert_eq!(it.next(), Some(5));

mapfilter 的工作方式不同,因为它们是迭代器适配器。一旦调用,返回的适配器值将拥有底层的迭代器,因此需要移动 self。即使值在该上下文中稍后被修改,也不必将其绑定到可变变量以将其移动到另一个范围。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接