std::rc::Rc necessitation for "unique ownership"?

The Gadget/Owner example in the documentation for std::rc::Rc confuses me quite a bit.

Consider a scenario where a set of Gadget s are owned by a given Owner . We want to have our Gadget s point to their Owner . We can't do this with unique ownership, because more than one gadget may belong to the same Owner.

I don't really understand this. Can't I just define a struct like:

struct Gadget<'a> {
    id: i32,
    owner: &'a Owner,
}

and have the Gadgets point to the owner like that? Rust's ownership rules say that you can have multiple immutable references to one thing. Why did the example choose to use std::rc::Rc here other than to ensure that the Gadgets lived beyond the Owner? I understand that it helped when drop(gadget_owner) was called, but the "unique ownership" line confuses me.

Here's a playground link of what I did.

What you did works for some situations, and leads to headache in others. Most limiting is that you can't create a new Gadget with a new Owner and freely move around the gadget, e.g. by returning it - the owner would be dropped and the reference point to nothing.

Edit: to make this a bit more concrete and show it can happen very easily, consider this seemingly innocuous example derived from yours:

#[derive(Debug)]
struct Owner { name: String }

#[derive(Debug)]
struct Gadget<'a> { id: i32, owner: &'a Owner }

fn main() {
    let gadget_owner = Owner { name: "Gadget Man".to_string() };
    let gadget1 = Gadget { id: 1, owner: &gadget_owner };

    let mut gadgets = vec![gadget1];

    let gadget_owner2 = Owner { name: "Gadget Man".to_string() };
    let gadget2 = Gadget { id: 2, owner: &gadget_owner2 };
    
    gadgets.push(gadget2);

    println!("Gadgets: {:?}", gadgets);
}

It will fail to compile since the lifetime in the vector (which has type Vec<Gadget<'a>>) outlives the one of the second owner.

1 Like

References are not pointers, but (compile time) locks on objects that make them read-only. It's not useful to have Owner permanently locked to be read-only.

Well, Rc is also a pretty effective read-only lock :slight_smile:

I’d also note that the value may expose internal mutability so it being immutable isn’t fully accurate.

Ah, I think I understand now. Rust doesn't like how gadget_owner2's lifetime is shorter than the Vec. I could move it above the Vec, but as you said, this is just complicating the issue further and can just be simplified using Rc. Thanks!

Fair point. However, Rc gives more flexibility, since the scope of the "lock" doesn't have to be limited to the static scope of the borrow.