What actually happens when I use `&`, `*`, and `ref`?

pub fn as_ref(&self) -> Option<&T> {  
      match *self {
         Some(ref x) => Some(x),
         None => None,
     }
}

This is a function of the option.
The '&self' in the code above 'create' an reference to the Option? But why in the match it needs a '*' ?

fn foo(v: &Vec<i32>) {
     v.push(5);
}

Why 'v' can be used directly?
In Java a reference just likes an alias of an object, why Rust need a '*'.
What's the difference between the two 'reference'?

Dose the ref x in the match branch mean let x = &x ?

1 Like

&self in fn as_ref(&self) is actually shorthand for: fn as_ref(self: &Self). It does not create a reference; it merely requires one to be passed to the function.


match doesn't need *self. It can also be written like so:

match self {
    &Some(ref x) => Some(x),
    &None => None,
}

They are broadly equivalent. The reason one or the other is needed is that self is of type &Self, and the match has to reflect that. You must either dereference the &Self to get a Self, then match on that or match on &Self and have that reflected in the patterns being used.


v.push(5) won't work in that example because Vec::push requires &mut self, but you have an immutable pointer.

So it would need to be:

fn foo(v: &mut Vec<i32>) { v.push(5); }

Now, that works because it's equivalent to Vec::push(v, 5); which matches the argument types exactly.


In Java a reference just likes an alias of an object, why Rust need a '*'. What's the difference between the two 'reference'?

Because Rust cares about the difference, Java doesn't. Java has only one kind of reference; Rust has (off the top of my head):

  • &T
  • &mut T
  • *const T
  • *mut T
  • Box<T>
  • Rc<T>
  • Arc<T>
  • Unique<T> (technically still an unstable implementation detail, though)

Also, Java doesn't simply not require * on pointers, it wouldn't make any sense at all. You can't dereference a pointer in Java because there's no way to know the size of the thing behind the pointer.

It's broadly the same as the reason as why Rust doesn't allow you to use dynamically sized types as values, but that's tangential.


Dose the ref x in the match branch mean let x = &x ?

No; x doesn't exist prior to this.

ref x in Some(ref x) as a pattern is saying "bind to the value in this position by immutable reference to the name x". In this case, Self is actually Option<T>; thus, the interior of Some is a value of type T. Binding to this interior by reference means that x is of type &T; hence, wrapping it in Some again produces an Option<&T>, which is what gets returned.

5 Likes

To perhaps clarify, let ref x = y; is equivalent to let x = &y;. You can't write the latter if x is nested in a destructuring pattern though, so in that case you need to use the first notation.

4 Likes