Learning about references and ownership

Hi all :wave:

In the Brown University version of The Book, the summary of chapter 4.2 says...

References provide the ability to read and write data without consuming ownership of it.

...but earlier in the chapter it shows this code...

let mut v: Vec<i32> = vec![1, 2, 3];
let num: &i32 = &v[2];

...and then shows that v has lost the O permission, and num has gained the O permission. To me it seems that the num reference has "consumed ownership" of the data!

What am I missing?

The fact that when num is no longer used you would get the ability to use v again.

That's why it's called โ€œborrowingโ€: reference gets temporary ownership over something (just like in real life: when you rent a car no one else use it simultaneously with you) but when loans time ends โ€” object may be used directly or can be loaned to someone else, again (just like in real life with real objects, again).

Rust's ownership model has special behaviours for mutable (better referred to as unique) or immutable (better referred to as shared) references. You can have either one unique reference or multiple shared references. This is sometimes referred to as "Aliasing XOR Mutability".

Okay, none of the other people read the part you looked at because it's not saying num has ownership over v. num has O and R over the reference itself. And then through the reference (*num), it has R on the first element of v.

Ownership over itself means it can make references to the reference, or give ownership of the reference to other variables, but it can't gain ownership over the value behind the reference.

let num2: &&i32 = &num; // reference given to num2
let num3: &i32 = num; // ownership transferred to num3
// let num4: i32 = *num; // Technically this works because `i32` implements `Copy`,
                         // but for other types it would be a compile error

When v loses O by giving out a reference, nobody gains its ownership. It just doesn't exist until num is dropped.

2 Likes

Thank you, @drewtato! I think I understand now. The section you linked (which is indeed the "earlier" part I was talking about), says this about ownership:

Own (O): data can be moved or dropped.

I believe one example of a "move" is direct assignment to another variable, so I added to the example:

let mut v: Vec<i32> = vec![1, 2, 3];

let num: &i32 = &v[2];
//  ^^^^^^^^^^^^^^^^^^ This is a borrow, so `v`
// has temporarily given up O (i.e. `v` cannot
// be directly assigned to another variable)

let v2 = v; 
//  ^^^^^^^ This is a move, but it's illegal!
// Due to the `println` of `num` below, the
// compiler does not allow `v` to have O back
// just yet (i.e. `v` still cannot be directly
// assigned to another variable).

println!("{:?}", num);

And I get an error from the compiler that seems to confirm my comments above:

error[E0505]: cannot move out of `v` because it is borrowed
 --> src/main.rs:4:14
  |
2 |     let mut v: Vec<i32> = vec![1, 2, 3];
  |         ----- binding `v` declared here
3 |     let num: &i32 = &v[2];
  |                      - borrow of `v` occurs here
4 |     let v2 = v;
  |              ^ move out of `v` occurs here
5 |     println!("{:?}", num);
  |                      --- borrow later used here
2 Likes

Yes, this is indeed an example of a move, which requires ownership permission.

1 Like

The thing is, you were confusing ownership of the reference with ownership of the referent.

Every value has to have some owner; you can't create a reference that has "no owner". Note that I'm not saying that you can't create a reference to a value that has no owner; I'm specifically talking about the reference itself, with no regard to its referent. The point is, Rust's type system is very regular. A reference is just like any other type. If you have a value of reference type, you can move it, borrow it again, or in general, do anything with it that you would do with any other type. And, by the very definition of a reference, owning a reference means borrowing its referent. It's as simple as that.

2 Likes

Thank you for the additional context, @paramagnetic! It's very helpful to think in terms of the reference itself, with no regard to its referent.