0

I'm trying to wrap my head around Rust objects lifetime. As I was performing a relationship modeling exercise I ran into the following error.

error: cannot borrow `bob` as mutable because `bob.gender` is also borrowed as immutable [E0502]

The code is here:

// Business Case:
// Design a person type.  A person may own a Car.  A person should be able to buy and sell cars.
// Two persons should be able to exchange (or trade) their cars.
//
// Purpose of exercise:
// Understand lifetime management in Rust while modeling containment relationship.
// (meaning: when an object contains a reference to another object.)

struct Car {
    make: &'static str,
    model: &'static str,
    year: &'static str,
}

struct Person<'a> {
    name: &'static str,
    gender: &'static str,
    car: Option<&'a Car>,
}

impl<'a> Person<'a> {
    fn new(name: &'static str, gender: &'static str, car: Option<&'a Car>) -> Person<'a> {
        Person {
            name: name,
            gender: gender,
            car: None,
        }
    }

    fn buy_car(&mut self, c: &'a Car) {
        self.car = Some(c);
    }

    fn sell_car(&mut self) {
        self.car = None;
    }
}

fn main() {
    let pickup = Car {
        make: "Ford",
        model: "F250",
        year: "2006",
    };

    let mut bob = Person::new("Bob", "Male", None);

    println!("A {:?} whose name is {:?} has just purchased a 2006 {:?}.",
             bob.gender,
             bob.name,
             bob.buy_car(&pickup));
}

Can anyone chime in on what exactly am I missing here? I'm not exactly sure if reference count or Box is the way to go, need a bit more insight.

Alex
  • 367
  • 2
  • 4
  • 14

1 Answers1

1

Your issue boils down to you using buy_car (which returns nothing) where you probably meant to use bob.car. To do that.. you'll want to have fmt::Debug implemented for your Car struct as well. Here is a working fix for you.. note all of the // <----- parts I added (here it is on the Playground):

#[derive(Debug)] // <------------ Have the compiler implement fmt::Debug for you
struct Car {
    make: &'static str,
    model: &'static str,
    year: &'static str,
}

struct Person<'a> {
    name: &'static str,
    gender: &'static str,
    car: Option<&'a Car>,
}

impl<'a> Person<'a> {
    fn new(name: &'static str, gender: &'static str, car: Option<&'a Car>) -> Person<'a> {
        Person {
            name: name,
            gender: gender,
            car: None,
        }
    }

    fn buy_car(&mut self, c: &'a Car) {
        self.car = Some(c);
    }

    fn sell_car(&mut self) {
        self.car = None;
    }
}

fn main() {
    let pickup = Car {
        make: "Ford",
        model: "F250",
        year: "2006",
    };

    let mut bob = Person::new("Bob", "Male", None);

    bob.buy_car(&pickup);   // <------- Buy the car separately

    println!("A {:?} whose name is {:?} has just purchased a 2006 {:?}.",
             bob.gender,
             bob.name,
             bob.car); // <------------ Pass the car into the debug string
}

As an aside - I would look in to using String where appropriate to reduce the need to pass references and lifetimes around. Maybe not so important in your small example but as the code gets bigger they can become tricky.

Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138
  • Ok, so I failed to use fmt::Debug trait and also call the struct method into my variable. I was a bit thrown off by the compiler error. I thought it may have had to do with some lifetime rule. As far as your other comment, I would just be replacing String with the static lifetime str, &'static str? – Alex Aug 24 '16 at 03:48
  • @Alex Here is an example of how you can have a `String` for your type's property.. but accept a `&'static str`, `&str` or `String` as input for it: https://play.rust-lang.org/?gist=5dc13bf0a53c9ad0ecc0d40e63072ff5&version=stable&backtrace=0. You don't _have_ to do this in your small sample.. but as your code gets bigger and you're passing references around (mutable, immutable, etc) it can become tricky. – Simon Whitehead Aug 24 '16 at 03:59
  • Understood, thank you so much for all your feedback. I will make the changes you recommended on my end. The playground was really helpful. – Alex Aug 24 '16 at 04:05