0

Here is an example of some structs:

enum VehicleType {
    Car,
    Motorcycle,
}

struct Vehicle {
    name: String,
    horsepowers: i32,
    vehicle_type: VehicleType,
}

struct Person<'a> {
    vehicle: &'a Vehicle,
    name: &'a str,
}

and in main function:

let mut car = Vehicle {
        name: "Nissan GTR".to_string(),
        horsepowers: 300,
        vehicle_type: VehicleType::Car,
    };

    let alice = Person {
        name: "Alice",
        vehicle: &car, // Share a reference to the same car
    };

    let bob = Person {
        name: "Bob",
        vehicle: &car, // Share a reference to the same car
    };

    println!("{} drives {}", alice.name, alice.vehicle.name);
    println!("{} drives {}", bob.name, bob.vehicle.name);

Now let's say we want to update the name of the car while preserving that Alice and Bob drive the same car

car.name = "Lamborghini".to_string();
car.horsepowers = 684;

println!("{} drives {}", alice.name, alice.vehicle.name);
println!("{} drives {}", bob.name, bob.vehicle.name);

This of course fails because car is borrowed by both Alice and Bob.

Why wouldn't rust compiler allow this? How does this introduce memory safety issues? How to go about a pattern like this?

Davo
  • 526
  • 3
  • 19
  • 1
    Does this answer your question? [Cannot borrow as mutable because it is also borrowed as immutable](https://stackoverflow.com/questions/47618823/cannot-borrow-as-mutable-because-it-is-also-borrowed-as-immutable) – cafce25 Dec 09 '22 at 15:44
  • 2
    If you want to create a mutable object that more than one other object share references to, you'll want to use `Rc>` to wrap the shared object. For instance, make an object called `FamilyCar` that has a field in it for the car, which can be changed. `Person` can have a field like, `car: Rc>` – Todd Dec 10 '22 at 04:23
  • You marked `alice` and `bob` as immutable, yet you want to change them. This is exactly the kind of thing Rust aims to prevent. – BallpointBen Dec 10 '22 at 05:32
  • @Todd No need for `Rc`, `&RefCell` will suffice. – Chayim Friedman Dec 10 '22 at 20:26
  • 1
    The answer to "how doees this introduce a memory safety issue", is "this is probably fine, but shared mutability was proved to be hard to reason about in decades of engineering". – Chayim Friedman Dec 10 '22 at 20:27
  • @ChayimFriedman to share the object between two other objects, I do believe you'll need Rc<>. – Todd Dec 12 '22 at 07:08
  • @Todd There is already a reference, so it can stay there. – Chayim Friedman Dec 12 '22 at 08:51

1 Answers1

1

You cannot mutate an object when it is immutably borrowed. If you want to reference the same Vehicle object in the Person structs and be able to mutate it, you may want to use a reference to a RefCell<T>:

use std::cell::RefCell;

enum VehicleType {
    Car,
    Motorcycle,
}

struct Vehicle {
    name: String,
    horsepowers: i32,
    vehicle_type: VehicleType,
}

struct Person<'a> {
    vehicle: &'a RefCell<Vehicle>,
    name: &'a str,
}

fn main() {
    let mut car = RefCell::new(Vehicle {
        name: "Nissan GTR".to_string(),
        horsepowers: 300,
        vehicle_type: VehicleType::Car,
    });

    let alice = Person {
        name: "Alice",
        vehicle: &car,
    };

    let bob = Person {
        name: "Bob",
        vehicle: &car,
    };

    println!("{} drives {}", alice.name, alice.vehicle.borrow().name);
    println!("{} drives {}", bob.name, bob.vehicle.borrow().name);

    car.borrow_mut().name = "Lamborghini".to_string();
    car.borrow_mut().horsepowers = 684;

    println!("{} drives {}", alice.name, alice.vehicle.borrow().name);
    println!("{} drives {}", bob.name, bob.vehicle.borrow().name);
}

NB: i32 is a poor choice for the horsepower of the car, since a negative horsepower does not make any sense. Consider using u32 instead.

Richard Neumann
  • 2,986
  • 2
  • 25
  • 50
  • 2
    Note that depending on the actual usage, `Rc` may be overkill. The example works with just plain `&RefCell` ([playground](https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=d26ca6b15c2340b7a26c3c6bf42b7112)) – Jmb Dec 09 '22 at 19:18