Почему я могу напрямую сопоставить массив опций, но не переменную, содержащую массив опций? - PullRequest
0 голосов
/ 24 июня 2018

Компилируется следующий код:

fn consume(_: Box<u64>) {}
let tuple = (Some(Box::new(1)), Some(Box::new(2)));
match tuple {
    (Some(x), Some(y)) => {
        consume(x);
        consume(y);
    }
    _ => (),
}

Компилируется следующий код:

fn consume(_: Box<u64>) {}
match [Some(Box::new(1)), Some(Box::new(2))] {
    [Some(x), Some(y)] => {
        consume(x);
        consume(y);
    }
    _ => (),
}

Но этот код не компилируется:

fn consume(_: Box<u64>) {}
let array = [Some(Box::new(1)), Some(Box::new(2))];
match array {
    [Some(x), Some(y)] => {
        consume(x);
        consume(y);
    }
    _ => (),
}

Компилятор говорит:

error[E0382]: use of moved value: `(array[..] as std::prelude::v1::Some).0`
 --> src/main.rs:5:24
  |
5 |         [Some(x), Some(y)] => {
  |               -        ^ value used here after move
  |               |
  |               value moved here
  |
  = note: move occurs because the value has type `std::boxed::Box<u64>`, which does not implement the `Copy` trait

Почему компилируется первая и вторая версии, а не третья версия?

Ответы [ 2 ]

0 голосов
/ 24 июня 2018

Вот сокращенная версия вашего кода:

struct NonCopy;

fn main() {
    // OK
    let tuple = (Some(NonCopy), Some(NonCopy));
    if let (Some(_x), Some(_y)) = tuple {}

    // OK
    if let [Some(_x), Some(_y)] = [Some(NonCopy), Some(NonCopy)] {}

    // Fails
    let array = [Some(NonCopy), Some(NonCopy)];
    if let [Some(_x), Some(_y)] = array {}
}

Хорошие новости

Этот код работает как есть, когда включены нелексические времена жизни .

Плохие новости

Нелексические времена жизни еще не стабильны.

Обходной путь

Явно передать владение массивом выражению заголовка match или if let:

let array = [Some(NonCopy), Some(NonCopy)];
if let [Some(_x), Some(_y)] = { array } {}

Объяснение

Текущая реализация средства проверки заимствований основана на AST, а будущая реализация будет основана на MIR. На высоком уровне вы можете думать об этом как о «работе над кодом в том виде, в котором я его набрал» (AST) и «работе над логическим потоком данных в моем коде» (MIR).

Определенные «хаки» были добавлены в средство проверки заимствования AST, поэтому вы можете успешно использовать литерал массива, но не переменную. При использовании средства проверки заимствований MIR такие большие хаки исчезают, а средство проверки заимствований также становится более точным, что позволяет компилировать больше кода.

0 голосов
/ 24 июня 2018

Неожиданно, что третья версия не компилируется. Та же проблема возникает при сопоставлении значений в штучной упаковке, как описано здесь .

Ссылаясь на объяснение ошибки из связанного ответа:

Мое единственное предположение, что право собственности на Box перенесено на первое параметр извлекается, затем компилятор пытается его переместить снова к следующему параметру.

Замените "Box" на "массив", и вы получите объяснение того, что происходит при сопоставлении массива. Одно из решений, представленных в связанном ответе, также работает для сопоставления массивов - использование фигурных скобок для принудительного полного перемещения массива Box / в выражение соответствия:

fn consume(_: Box<u64>) {}
let array = [Some(Box::new(1)), Some(Box::new(2))];
match {array} {
    [Some(x), Some(y)] => {
        consume(x);
        consume(y);
    }
    _ => (),
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...