flooblebit
flooblebit

Reputation: 547

How do I retrieve an item from a Vec that is moved into a structure?

I have a structure which contains a Vector of structs, e.g.

fn main() {
    let x: Vec<Item> = Vec::new(); 
    // assume x is filled with stuff
    do_things_with(x);
}

struct Item {
    value: String,
}

struct Context {
    x: Vec<Item>,
}

impl Context {
    fn get(&mut self, at: usize) -> Item {
        self.x[at]
    }
}

fn do_things_with(x: Vec<Item>) {
    let mut ctx = Context{
        x: x,
    };
    ctx.get(5);
}

I have a Vec of stuff, and I pass this to some function which creates a context and stores the passed value in that structure. I then want to look at the items in this Vec so I have some helper functions, e.g. 'get' which will get the item at the index specified.

This seems all good, and in C or whatever language it would be fine, however Rust complains:

'cannot move out of borrowed content'

For the function 'get' where we try to access the item in the vector.

What am I doing wrong here?

Upvotes: 1

Views: 493

Answers (1)

chucksmash
chucksmash

Reputation: 6017

The problem here is that the Vec has ownership of the Items it contains, but Context.get is trying to return the Item directly (and take ownership of it).

If Context.get just needs to let callers peek at the contents of the vector, it should return a reference to an Item instead of an Item:

impl Context {
    fn get(&mut self, at: usize) -> &Item {
        &self.x[at]
    }
}

In the above case, Context.get can take an immutable reference to self since it is not changing anything. Further, if you want to allow callers of Context.get to modify the referenced Item, you would return &mut Item instead of &Item:

impl Context {
    fn get(&mut self, at: usize) -> &mut Item {
        &mut self.x[at]
    }
}

Edit: As @apemanzilla helpfully notes in the comments, you could also have Item implement the Clone trait if you want Context.get to return a separate copy of the Item at at:

#[derive(Clone)]
struct Item {
    value: String,
}

impl Context {
    fn get(&mut self, at: usize) -> Item {
        self.x[at].clone()
    }

Changing the returned Item will not modify the one contained in self.x though; this may or may not be what you intended.

Upvotes: 2

Related Questions