В Rust очень мощная система сопоставления с образцом. Вы можете сопоставлять литералы, структуры, перечисления, срезы (различной длины), определенные поля в структуре (путем деконструирования), вложенные поля, ссылки, диапазоны и т. Д.

Предполагая, что мы хорошо разбираемся в сопоставлении с образцом в Rust, давайте рассмотрим ключевое слово ref и взаимосвязь между ref и &, когда дело доходит до сопоставления с образцом.

Eg1:

let x:i32 = 1;
match x {
  ref y => println!("{}", *y),
  _ => ()
}

Приведенный выше фрагмент является очень простым примером (Очевидно, что условие «по умолчанию» никогда не будет выполнено. Но здесь мы можем проигнорировать это в интересах этой темы). В основном ref вступает в игру после матча. т.е. «Сопоставить, а затем рассматривать связанную переменную как ссылку». Здесь переменная y привязана к ссылке x после совпадения.

Давайте посмотрим на следующий пример:

Eg2:

let x:i32 = 1;
match &x {
  y => println!("{}", *y),
  _ => ()
}

Здесь операнд для match является ссылкой, что означает, что переменная y будет привязана ко всему операнду. Вот еще один пример,

Eg3:

let x:i32 = 1;
match &x {
  &y => println!("{}", y),
  _ => ()
}

Операнд &x деформируется в случае (&y), и только часть значения y извлекается (копируется). Обратите внимание на разницу; & принимает участие в процессе сопоставления, а ref - нет. В этом примере будет ошибка компиляции, если операнд не является ссылкой.

Eg1 лучше с точки зрения удобочитаемости. На самом деле нет необходимости явно брать ссылку и передавать ее блоку match, а что, если тип не Copy? Eg3 не будет компилироваться, так как вы не можете переместить значение, если оно находится за ссылкой.

Давайте посмотрим еще на несколько примеров.

Вот пример, в котором мы деконструируем настраиваемый тип (перечисление) и берем ссылки на поля его вариантов.

enum Shape {
  Circle(u8),
  Rectangle(u8, u8),
  Triangle(u8, u8)
}
// where `shape` is an instance of `Shape` 
match shape {
   // `radius` is of type &u8, due to ref
   Circle(ref radius) => circle_area(radius),
   // `length` and `width` are of type &u8, due to ref
   Rectangle(ref length, ref width) => rect_area(length, width), 
   // `base` and `height` are of type &u8, due to ref
   Triangle(ref base, ref height) => triangle_area(base, height) 
}

Вот пример, в котором мы деконструируем struct, а затем сопоставляем одно из его полей и берем ссылку на другое.

enum FoodType {
    Soda,
    Pizza
}
struct Details {
    name : String,
    calories : u16,
}
struct Food {
    category : FoodType,
    details : Details
}
fn consume(p: Food) {
    match p {
        Food {
            category: Soda,
            details: ref d,
        } => sip(d),
        Food {
            category: Pizza,
            details: ref d,
        } => bite(d),
    }
}

Что, если вместо этого мы передадим &p блоку match? Будет ли это компилироваться?

Да! он компилируется. Обратите внимание на образцы в корпусах. Все они являются значениями, поэтому для сопоставления компилятор сначала выполняет автоматическое разыменование (*p). Если бы он был &&p, то он дважды автоматически разыграл бы и так далее ...

Подразумевается, что d является ссылкой, поскольку операнд был ссылкой.

Итак, нужно ли нам оставить ключевое слово ref? Хотя код все еще компилируется, ref в этом сценарии является избыточным, и он нам здесь не нужен.

fn consume(p: Food) {
    match &p {  // could very well be &&p, &&&p ...
        Food {
            category: Soda,
            details: d, // `ref d` or `d`,both are same i.e &Details
        } => sip(d),
        Food {
            category: Pizza,
            details: d, // `ref d` or `d`,both are same i.e &Details
        } => bite(d),
    }
}

Другое менее известное использование (вне сопоставления с образцом) - это ссылка на переменную.

В основном следующий фрагмент:

let y = &mut x;

можно записать как

let ref mut y = x;

Вот и все! Надеюсь, эта краткая статья окажется для вас информативной.