Help understanding the `ref t` syntax

Hello, I need some help understanding the ref t syntax.

From: https://doc.rust-lang.org/std/option/index.html#options-and-pointers-nullable-pointers

fn check_optional(optional: Option<Box<i32>>) {
    match optional {
        Some(ref p) => println!("has value {}", p),

Here the statement is that try to pull Box<i32> as a ref p. In equation terms- ref p = Box(9). Deref both sides => p = Box(9).deref(). p = 9.

But from: https://doc.rust-lang.org/std/option/index.html#examples

msg = Some( "howdy" )
if let Some(ref m) = msg {

doesn't seem to be following that equation, Some( "howdy" ) = Some(ref m) => m = "howdy".deref() ?

How do I understand the ref syntax conceptually?

Is this deliberately inconsistent for language ergonomics?

Only to mention- Scala would have done it slightly differently which would have been clearer too-

1-

match optional{
  Some( Ref( p ) ) => ...

2-


if let Some(Deref(m)) = msg 

This is both mathematically consistent and IMHO easier to glance.

ref is not related to Deref. The deref coercion is automatically inserted to some places but doesn't affect the matched variables directly.

If type T is matched to ref x then type of x is &T. But then why not just match for x and use &x? Consider this code:

#[derive(Debug)]
struct S;
fn use_s(_: &S) {}

let x: Option<S> = Some(S);
if let Some(ref y) = x {
    /* y : &S */
    use_s(y);
}
dbg!(x);

If I remove ref,

if let Some(y) = x {
    /* y : S */
    use_s(&y);
}
dbg!(x);

It doesn't compile. The error tells use x is moved by the pattern matching but later used.

It is similar to that "&some_struct.field" doesn't move some_struct out.
Technically, pattern matching matches against "place" instead of "value" (if you are familiar with C++, you can read "place" as "lvalue").

Today, the ref pattern is almost superseded by the "match ergonomics" which automatically insert & pattern and ref pattern to appropriate places.
The Option example can be written as:

let msg: Option<&str> = Some("howdy");
if let Some(m) = &msg { /* m : &&str */ }
2 Likes