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

时间:2018-02-26 16:41:29

标签: iterator rust

我在template<class...> struct voider { using type = void; }; template<class...Ts> using void_t = typename voider<Ts...>::type; template<template<class...> class Test, class Tuple> struct get_first_pass; template<template<class...> class Test, class Tuple> using get_first_pass_t = typename get_first_pass<Test, Tuple>::type; template<template<class...> class, class, class...> struct first_pass {}; template<template<class...> class Test, class T0, class...Ts> struct first_pass<Test, std::enable_if_t<!Test<T0>::value>, T0, Ts...> : first_pass<Test, void, Ts...> {}; template<template<class...> class Test, class T0, class...Ts> struct first_pass<Test, std::enable_if_t<Test<T0>::value>, T0, Ts...> { using type = T0; }; template<template<class...> class Test, template<class...> class Tuple, class...Ts> struct get_first_pass<Test, Tuple<Ts...>> : first_pass<Test, void, Ts...> {}; template<class Base> struct is_derived_from { template<class Derived> using test = std::is_base_of<std::decay_t<Base>, std::decay_t<Derived>>; }; template<class Base, class Tuple> using get_first_derived = get_first_pass_t<is_derived_from<Base>::template test, Tuple>; template<class Base, class Tuple> auto get_from_base(Tuple&& tuple) -> decltype(std::get< get_first_derived<Base, std::decay_t<Tuple>> >( std::forward<Tuple>(tuple))) { return std::get< get_first_derived<Base, std::decay_t<Tuple>> >( std::forward<Tuple>(tuple)); } 个字符上使用了迭代器:

String

这会引发编译错误:

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方法不应该改变迭代器。与allmap一样,以filter而不是self作为参数。

我的reference for map / filter / all

我看到了an issue on the matter,但没有给出任何解释。

2 个答案:

答案 0 :(得分:5)

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

  

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

我很想知道如何在没有调用next的情况下检查迭代器中的每个值。

  

mapfilter

这些方法返回一个新的迭代器,它们不会调用next。话虽这么说,他们可以,如果他们想要因为......

  

self而非mut self作为参数。

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

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

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

答案 1 :(得分:3)

迭代器方法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。值不必绑定到可变变量即可移动到另一个范围,即使它们稍后在该上下文中被修改。