Why `Iter.find` require a mut ref?

#![allow(unused)]
fn main() {
    let arr = vec![(String::from("1"))];
    let iterator = arr.iter();
    let keyword = &iterator.find(|(&keyword)| keyword.eq("1")); // a
    println!("{:?}", keyword)
}

I have two questions:

First question:

Error occurs in the line with flag a, I am wonder why it should change to mut. Intuitively, only if I want to mutate the found element, I should decorate arr with mut and use arr.iter_mut.

Second question:

I try to fix it, When I use arr.iter() instead of &iterator, the error gone:

-let keyword = &iterator.find(|(&keyword)| keyword.eq("1"));
+let keyword = arr.iter().find(|(&keyword)| keyword.eq("1"));

But if I not inline arr.iter(), the error back again:

-let keyword = &iterator.find(|(&keyword)| keyword.eq("1"));
+let iterator = arr.iter();
+let keyword = iterator.find(|(&keyword)| keyword.eq("1")); 

Are there some differences between inline it or not inline it?

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0596]: cannot borrow `iterator` as mutable, as it is not declared as mutable
 --> src/main.rs:5:20
  |
4 |     let iterator = arr.iter();
  |         -------- help: consider changing this to be mutable: `mut iterator`
5 |     let keyword = &iterator.find(|(&keyword)| keyword.eq("1"));
  |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable

For more information about this error, try `rustc --explain E0596`.
error: could not compile `playground` due to previous error

You don't have to declare arr as mutable. You have to declare iterator as mutable, because iteration - and find in particular - obviously has to change its state (but not the source's state). See this playground.

If arr.iter is called inline, its return value is a temporary, and temporaries are always mutable.

5 Likes

…and then there’s always also the (slightly tricky) alternative of forcing a move, e.g. via a block expression.

    let iterator = arr.iter();
    let keyword = &{ iterator }.find(|(&keyword)| keyword.eq("1"));
2 Likes

Also, in &iterator.find(), the operator precedence means that this is interpreted as &(iterator.find()), not (&iterator).find().

1 Like
let a = ['R', 'u', 's', 't', ' ', '2', '0', '1', '8'];
let mut it = a.iter().copied();

// Iterator needs to be mutable because after using it once
assert_eq!(it.find(|x| *x == 'u'), Some('u'));
// You can then keep looking for new stuff
assert_eq!(it.find(|x| *x == '2'), Some('2'));
// But the iterator has moved over things,
// it's not looking from the beginning each time
assert_eq!(it.find(|x| *x == 't'), None);

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f4d028a76b0c81da79fff95e818758d9.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.