Moving the content of a vector without keeping a borrow on it

I'm trying to do something like this

struct Foo {
    commands: Vec<String>,
}

impl Foo {
    fn do_something(&self, _c: &mut String) {
        //...
    }
}

fn main() {
    let mut foo = Foo {
        commands: vec!["a".to_string(), "b".to_string()],
    };
    
    for command in foo.commands.iter_mut() {
        foo.do_something(command);
    }
    
    println!("All done");
}

Rightfully so the compiler complains as I have a borrow on both foo and commands at the same time.

error[E0502]: cannot borrow `foo` as immutable because `foo.commands` is also borrowed as mutable
  --> src/main.rs:17:9
   |
16 |     for command in foo.commands.iter_mut() {
   |                    ------------          - mutable borrow ends here
   |                    |
   |                    mutable borrow occurs here
17 |         foo.do_something(command);
   |         ^^^ immutable borrow occurs here

I found a way to work around this but I find it particularly inelegant yet I can't find another way

struct Foo {
    commands: Vec<String>,
}

impl Foo {
    fn do_something(&self, _c: &mut String) {
        //...
    }
}

fn main() {
    let mut foo = Foo {
        commands: vec!["a".to_string(), "b".to_string()],
    };
    
    let mut commands = Vec::new();
    loop {
        match foo.commands.pop() {
            Some(command) => commands.push(command),
            None => break,
        }
    }

    for command in commands.iter_mut() {
        foo.do_something(command);
    }
    
    println!("All done");
}

Is there a better way to do this? Thanks in advance for your help !!!


Playground links:
Top example
Bottom example (working yet inelegant)

Do you actually want to empty out the commands vector in foo? Your two examples do things differently in that regard, and so a bit unclear. But if you want to take all the elements out, you can do:

for mut command in std::mem::replace(&mut foo.commands, vec![]) {
        foo.do_something(&mut command);
}

Can't you add something like process_next_cmd(&mut self) -> Option<()> to your struct, which will use pop and do_something inside itself? Code from your example can look like this:

while let Some(()) = foo.process_next_cmd() { }

Instead of () you can use some kind of result type, to handle command execution results inside the loop.

Yes I do want to empty it (it’s in a builder sort of struct). Thanks for the solution. I never think about mem::transmute and it’s quite handy indeed.

That’s a different approach but it might work too I think. It’s smart as well. Thanks a lot too

Indeed - don't think about mem::transmute much :slight_smile: (I realize you meant mem::replace).

Another option, akin to what @newpavlov suggested but simpler:

 while let Some(mut cmd) = foo.commands.pop() {
        foo.do_something(&mut cmd);
}

This changes the order of processing, however, from the (forward) iterator loop.

1 Like

@vitalyd now that one is very elegant. I love it :slight_smile:

foo.commands.split_off(0).into_iter().for_each(|command| {
    foo.do_something(command);
}

What about this?