1

I am new to rust and trying to learn and experiment, here is a link to the playground with the issue and explanation below: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=19920813410a42500045cf2c6cc94f12

use std::fmt;

#[derive(Clone, Copy)]
struct Animal<'a> {
    name: &'a str
}

impl <'a>Animal<'a> {
    fn new(name: &'a str) ->  Self { Self { name } }    
}
struct Barn<'a> {
    name: &'a str,
    animals: Vec<Animal<'a>>
}

impl <'a> Barn<'a> {
    fn new(name: &'a str, animals: Vec<Animal<'a>>) ->  Self { Self { name, animals } }    
}

impl <'a>fmt::Debug for Barn<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.name)
    }
}

struct Farmer<'a> {
    name: &'a str,
    barns: Vec<Barn<'a>>
}

impl <'a> Farmer<'a> {
    fn new(name: &'a str, barns: Vec<Barn<'a>>) -> Self { Self { name, barns } }
    
    fn add_new_barn(&mut self, barn: Barn<'a>) {
        self.barns.push(barn)
    }
    
    fn place_animal_in_barn(&mut self, animal: Animal, placement: &str) {
        for barn in &self.barns {
            // how do I do make this work?
            if barn.name == placement {
                barn.animals.push(animal);
            }
        }
    }
}

impl <'a>fmt::Debug for Farmer<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:#?}", self.barns)
    }
}

fn main() {
    let mut farmer = Farmer::new("Farm Master Joe",
        vec![
            Barn::new("Tegridy Farms", vec![
                Animal::new("cow"), 
                Animal::new("horse"), 
                Animal::new("pigeon")
            ]), 
            Barn::new("Barney", vec![
                Animal::new("Purple Dinosaur"), 
                Animal::new("Green Dinosaur")
            ]), 
            Barn::new("White Rabbits R' Us", vec![
                Animal::new("white rabbit"),
            ])
        ]
    );
    
    println!("{:#?}", farmer.name);
    farmer.add_new_barn(Barn::new("The Good Place", vec![
        Animal::new("Horse"),
        Animal::new("Wombat")
    ]));
    
    farmer.place_animal_in_barn(Animal::new("Turkey"), "The Good Place");
    println!("{:#?}", farmer);
}

How do I fix this method, so I can push to the vector?

    fn place_animal_in_barn(&mut self, animal: Animal, placement: &str) {
        for barn in &self.barns {
            // how do I do make this work?
            if barn.name == placement {
                barn.animals.push(animal);
            }
        }
    }

I am getting the following error and I don't quite understand it or how to fix it:

  |
39 |         for barn in &self.barns {
   |                     ----------- this iterator yields `&` references
...
42 |                 barn.animals.push(animal);
   |                 ^^^^^^^^^^^^ `barn` is a `&` reference, so the data it refers to cannot be borrowed as mutable
  • 4
    Does this answer your question? [How can I do a mutable borrow in a for loop?](https://stackoverflow.com/questions/39622783/how-can-i-do-a-mutable-borrow-in-a-for-loop) Change `&self.barns` to `&mut self.barns`. – kmdreko Mar 18 '21 at 06:13

1 Answers1

5

After reading up on mutable borrows in for loops it looks like this is the solution:

    fn place_animal_in_barn(&mut self, animal: Animal<'a>, placement: &str) {
        for barn in &mut self.barns {
            if barn.name == placement {
                barn.animals.push(animal);
            }
        }
    }

link to playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=1ad9443801991ed12c6c112d78104cfa