Difference between four references


#1

Could someone please explain to me the difference between these four function definitions:

fn update(&state: KeyboardState) {...}
fn update(&mut state: KeyboardState) {...}
fn update(state: &KeyboardState) {...}
fn update(state: &mut KeyboardState) {...}

I’m pretty sure I get the & vs &mut, but I’m still unclear on the difference between putting it before and after the parameter name.

On a related note, here’s another question I’m not quite clear on: What’s the difference between a pointer and a reference? Thank you!


#2

The first two are not legal syntax, actually. I think what you meant was:

fn update(state: KeyboardState) { ... }
fn update(mut state: KeyboardState) { ... }

It’s a little clearer with variable bindings, rather than arguments, even though they’re the same:

let state: &KeyboardState;
let mut state: &KeyboardState;
let state: &mut KeyboardState;
let mut state: &mut KeyboardState;

These are the four options. In the second and fourth, the binding is mutable, and in the third and fourth, the reference is mutable. You can reassign a mutable binding, but you can modify what a mutable binding points to.

https://doc.rust-lang.org/book/mutability.html elaborates a bit; did you read it?

We tend to say “reference” always, because while references and C’s “pointers” are the same thing at an assembly level, C doesn’t check the validity of pointers, but Rust does check the validity of references. So in some sense, “reference” is a specific kind of pointer. Does that make sense?


#3

I did read the mutability chapter, but that was several weeks ago. Must have forgotten some parts.

Regarding the syntax, if

fn update(&state: KeyboardState) {..}

isn’t valid syntax, why doesn’t the compiler give me some form of syntax error? It just says:

error: mismatched types:
 expected `KeyboardState`,
    found `&_`
(expected struct `KeyboardState`,
    found &-ptr) [E0308]

And yes, the references explanation makes sense. Thank you!


#4

It’s perfectly valid syntax (steveklabnik has forgotten that the first part of a parameter is a pattern, not an identifier).

Because it’s a pattern, putting it there does roughly the opposite of what putting it in an expression does. If I write this:

let &v = &3i32;

v will be of type i32. Because the pattern &v was bound to &3, v was bound to 3. It destructured it. Function parameters work just like let bindings do.

With this information, it makes sense that you got a type error. You tried to bind KeyboardState to &k, but there’s no & on the one side to bind the & to on the other side.

This would be valid (though it will give an error in the borrow checker unless KeyboardState is copyable, because getting the KeyboardState out of a &KeyboardState requires copying it).

fn update(&state: &KeyboardState) {...}

#5

Also, we always say reference in regards to &T. *const T is a raw pointer, because the compiler does not track it at all.


#6

Thank you all for the help! Rust is different, but I think I’m getting there :slight_smile:


#7

I think the mutability docs have one confusing part:

let mut x = 5;

This is a mutable variable binding. When a binding is mutable, it means you’re allowed to change what the binding points to.

And then it says:

If you want to change what the binding points to, you’ll need a mutable reference:

Which is exactly the same phrase (“to change what the binding points to”). :smile:
I understand that the context is different, but this is so central and sometimes subtle (as the docs also say) that maybe another phrasing could be better.

The examples help a lot, though.


#8

Would this be a better phrasing?

You can also create a reference to it, using &x, but if you want to use the reference to change it, you will need a mutable reference.

let mut x = 5;
let y = &mut x;

y is an immutable binding to a mutable reference, which means that you can’t bind y to something else (y = &mut z), but y can be used to bind x to something else (*y = 5). A subtle distinction.

p.s. I will open a pull request, if you say yes.


#9

I like it! Please do.


#10

@notriddle It does help a lot! Thanks for taking the time.