rust

How to iterate over a vector without moving it


I have a recursive type which doesn't implement copy

struct Node {
    board: Board,
    children: Option<Vec<Node>>,
}

I have a Vector of these nodes, I want to call a method on each, and then pass them on to another function.

fn foo() {
    let mut nodes: Vec<Node> = get_nodes();
    for i in 0..nodes.len() {
        nodes[i].grow();
    }
    pick_node(nodes);
}

This works, but frustratingly

fn foo() {
    let nodes: Vec<Node> = get_nodes();
    for mut node in nodes {
        node.grow();
    }
    pick_node(nodes);
}

causes an error because "nodes moved due to this implicit call to .into_iter()"

Is there a version of for _ in _ that just gets me references to each member of the vector in turn, without moving or copying, like I get when I use a range like in the first version? It's an issue that comes up a lot for me, and it's been hard to find an answer for some reason. Like Clippy says, the iterator is probably faster, and clearer, and just seems idiomatic.


Solution

  • I believe the methods you're looking for are iter and/or iter_mut. So your code will look like the following:

    for node in nodes.iter_mut() {
        node.grow();
    }
    

    Alternatively, &Vec<T> and &mut Vec<T> both have IntoIterator implementations which return the iterator provided by iter or iter_mut respectively. So the following is also equivalent to the above:

    for node in &mut nodes {
        node.grow();
    }
    

    To add a little more clarification:

    for pattern in iterable {
        /* body */
    }
    

    essentially just desugars to the following:

    let mut iter = IntoIterator::into_iter(iterable);
    loop {
        match iter.next() {
            Some(pattern) => { /* body */ },
            None => break,
        }
    }
    

    into_iter requires an owned self, so that's why your vector is moved when it's substituted in the place of iterable. Ownership of the vector is transferred to its into_iter function. On the other hand, when you put &vec or &mut vec in the place of iterable, it's the references which are copied/moved, leaving the original vector in place.