Sid Holland
Sid Holland

Reputation: 2921

Mutate a struct within a vector within a struct

I'm attempting to mutate a struct that is a member of a vector within another struct. Despite reading the documentation and many, many articles on ownership, I'm still obviously missing something because I cannot get the following, relatively trivial code to work.

I'm getting a compiler error on the line add_content(&mut bar); which says cannot borrow data in a '&' reference as mutable, which I know is true, but I cannot figure how to get it to work.

I've been reading about Box<T>, Cell<T> and RefCell<T> and wondering if I might need to make use of one of those but I'm very unfamiliar with them and it seems like my trivial example below should work without extra complications.

#[derive(Debug)]
struct Foo {
    id: u32,
    bars: Vec<Bar>,
}

#[derive(Debug)]
struct Bar {
    id: u32,
    content: String,
}

fn main() {
    let mut foos: Vec<Foo> = Vec::new();
    foos.push(Foo {
        id: 100,
        bars: Vec::new(),
    });
    foos[0].bars.push(Bar {
        id: 200,
        content: String::new(),
    });
    loops(&foos);
    println!("{:#?}", foos);
}

fn loops(foos: &Vec<Foo>) {
    for foo in foos {
        for mut bar in &foo.bars {
            add_content(&mut bar);
        }
    }
}

fn add_content(bar: &mut Bar) {
    bar.content = String::from("hello");
}

Note that my example is deliberately trivial. My actual program is more involved but I've tried to boil down the problem to just the part that's giving me a headache.

How can I get the above code to work?

Upvotes: 2

Views: 335

Answers (3)

Gurwinder Singh
Gurwinder Singh

Reputation: 39457

You need to pass in mutable reference to vector because you are modifying elements of the vector.

#[derive(Debug)]
struct Foo {
    id: u32,
    bars: Vec<Bar>,
}

#[derive(Debug)]
struct Bar {
    id: u32,
    content: String,
}

fn main() {
    let mut foos: Vec<Foo> = Vec::new();
    foos.push(Foo {
        id: 100,
        bars: Vec::new(),
    });
    foos[0].bars.push(Bar {
        id: 200,
        content: String::new(),
    });
    loops(&mut foos);
    println!("{:#?}", foos);
}

fn loops(foos: &mut Vec<Foo>) {
    for foo in foos {
        for bar in &mut foo.bars {
            add_content(bar);
        }
    }
}

fn add_content(bar: &mut Bar) {
    bar.content = String::from("hello");
}

Upvotes: 2

Jmb
Jmb

Reputation: 23245

You need to add mut at every level of your data hierarchy:

fn loops(foos: &mut Vec<Foo>) {
    for foo in foos {
        for mut bar in &mut foo.bars {
            add_content(&mut bar);
        }
    }
}

Upvotes: 0

QuarticCat
QuarticCat

Reputation: 1526

Obviously, you can not borrow a &mut from a &. And it seems that you messed up the types of foo bar. Change your code into something like this:

fn main() {
    let mut foos: Vec<Foo> = Vec::new();
    foos.push(Foo {
        id: 100,
        bars: Vec::new(),
    });
    foos[0].bars.push(Bar {
        id: 200,
        content: String::new(),
    });
    loops(&mut foos);  // look at here
    println!("{:#?}", foos);
}

fn loops(foos: &mut Vec<Foo>) {  // here
    for foo in foos {
        for bar in &mut foo.bars {  // here
            add_content(bar);  // and here
        }
    }
}

or

fn main() {
    // the same
}

fn loops(foos: &mut Vec<Foo>) {
    for foo in foos.iter_mut() {
        for bar in foo.bars.iter_mut() {
            add_content(bar);
        }
    }
}

Upvotes: 2

Related Questions