Why is `ref` used instead of an asterisk in pattern matching?

拥有回忆 提交于 2021-01-07 02:52:32

问题


I am having trouble trying to understand pattern matching rules in Rust. I originally thought that the idea behind patterns are to match the left-hand side and right-hand side like so:

struct S {
    x: i32,
    y: (i32, i32)
}
let S { x: a, y: (b, c) } = S { x: 1, y: (2, 3) }; 
// `a` matches `1`, `(b, c)` matches `(2, 3)`

However, when we want to bind a reference to a value on the right-hand side, we need to use the ref keyword.

let &(ref a, ref b) = &(3, 4);

This feels rather inconsistent.

Why can't we use the dereferencing operator * to match the left-hand side and right-hand side like this?

let &(*a, *b) = &(3, 4);
// `*a` matches `3`, `*b` matches `4`

Why isn't this the way patterns work in Rust? Is there a reason why this isn't the case, or have I totally misunderstood something?


回答1:


Using the dereferencing operator would be very confusing in this case. ref effectively takes a reference to the value. These are more-or-less equivalent:

let bar1 = &42;
let ref bar2 = 42;

Note that in let &(ref a, ref b) = &(3, 4), a and b both have the type &i32 — they are references. Also note that since match ergonomics, let (a, b) = &(3, 4) is the same and shorter.

Furthermore, the ampersand (&) and asterisk (*) symbols are used for types. As you mention, pattern matching wants to "line up" the value with the pattern. The ampersand is already used to match and remove one layer of references in patterns:

let foo: &i32 = &42;

match foo {
    &v => println!("{}", v),
}

By analogy, it's possible that some variant of this syntax might be supported in the future for raw pointers:

let foo: *const i32 = std::ptr::null();

match foo {
    *v => println!("{}", v),
}

Since both ampersand and asterisk could be used to remove one layer of reference/pointer, they cannot be used to add one layer. Thus some new keyword was needed and ref was chosen.

See also:

  • Meaning of '&variable' in arguments/patterns
  • What is the syntax to match on a reference to an enum?
  • How can the ref keyword be avoided when pattern matching in a function taking &self or &mut self?
  • How does Rust pattern matching determine if the bound variable will be a reference or a value?
  • Why does pattern matching on &Option<T> yield something of type Some(&T)?



回答2:


In this specific case, you can achieve the same with neither ref nor asterisk:

fn main() {
    let (a, b) = &(3, 4);

    show_type_name(a);
    show_type_name(b);
}

fn show_type_name<T>(_: T) {
    println!("{}", std::any::type_name::<T>()); // rust 1.38.0 and above
}

It shows both a and b to be of type &i32. This ergonomics feature is called binding modes.

But it still doesn't answer the question of why ref pattern in the first place. I don't think there is a definite answer to that. The syntax simply settled on what it is now regarding identifier patterns.



来源:https://stackoverflow.com/questions/58184472/why-is-ref-used-instead-of-an-asterisk-in-pattern-matching

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!