Почему в сопоставлении с образцом используется `ref` вместо звездочки? - PullRequest
0 голосов
/ 01 октября 2019

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

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)`

Однако, когда мы хотим привязать ссылку кзначение справа, нам нужно использовать ключевое слово ref.

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

Это выглядит довольно непоследовательным.

Почему мы не можем использовать оператор разыменования *чтобы подобрать левую и правую стороны следующим образом?

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

Почему шаблоны в Rust не работают так? Есть ли причина, по которой это не так, или я что-то не так понял?

Ответы [ 2 ]

2 голосов
/ 01 октября 2019

Использование оператора ссылок de будет очень запутанным в этом случае. ref эффективно принимает ссылку на значение. Они более или менее эквивалентны:

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

Обратите внимание, что в let &(ref a, ref b) = &(3, 4), a и b оба имеют тип &i32 - они являются ссылками. Также обратите внимание, что, поскольку соответствует эргономике , let (a, b) = &(3, 4) является таким же и более коротким.

Кроме того, символы амперсанда (&) и звездочки (*) используются для типов. Как вы упомянули, при сопоставлении с образцом требуется «выровнять» значение с шаблоном. Амперсанд уже используется для сопоставления и удаления одного слоя ссылок в шаблонах:

let foo: &i32 = &42;

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

По аналогии, возможно, что в будущем будет поддерживаться некоторый вариант этого синтаксиса для rawуказатели:

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

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

Поскольку амперсанд и звездочка могут использоваться для удаления одного уровня ссылки / указателя, их нельзя использовать для добавления одного слоя. Таким образом, было необходимо новое ключевое слово и было выбрано ref.

См. Также:

0 голосов
/ 01 октября 2019

В этом конкретном случае вы не можете достичь того же самого, не используя ref и звездочку:

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
}

Это показывает, что a и b имеют тип &i32. Эта эргономическая функция называется режимами привязки .

Но она по-прежнему не отвечает на вопрос, почему шаблон ref в первую очередь. Я не думаю, что есть определенный ответ на это. Синтаксис просто определился с тем, что он сейчас имеет в отношении шаблонов идентификаторов .

...