Смещенная по ошибке ошибка при деконструкции бокса пар

Следующие две строки:

let x = Box::new(("slefj".to_string(), "a".to_string()));
let (a, b) = *x;

выдать ошибку:

error[E0382]: use of moved value: `x`
 --> src/main.rs:3:13
  |
3 |     let (a, b) = *x;
  |          -  ^ value used here after move
  |          |
  |          value moved here
  |
  = note: move occurs because `x.0` has type `std::string::String`, which does not implement the `Copy` trait

Интересно, что если я делаю это с типом перечисления с несколькими частями, я получаю немного другую ошибку:

enum Tree {
    Nil,
    Pair(Box<Tree>, Box<Tree>),
}

fn main() {
    let x = Box::new(Tree::Nil);

    match *x {
        Tree::Pair(a, b) => Tree::Pair(a, b),
        _ => Tree::Nil,
    };
}

Я получаю ошибку:

error[E0382]: use of collaterally moved value: `(x:Tree::Pair).1`
  --> src/main.rs:10:23
   |
10 |         Tree::Pair(a, b) => Tree::Pair(a, b),
   |                    -  ^ value used here after move
   |                    |
   |                    value moved here
   |
   = note: move occurs because `(x:Tree::Pair).0` has type `std::boxed::Box<Tree>`, which does not implement the `Copy` trait

Почему это происходит, и как я могу легко разрушить структуры let/match и получить право собственности на внутренние части? Я знаю, что сначала могу разыскивать и называть структуру, но это становится ужасно многословным, если я сопоставляю паттерны глубоко в структуре.

2 ответа

Вы наткнулись на ограничение на деструктуризацию и боксы. К счастью, обойти это легко. Все, что вам нужно сделать, это ввести новую промежуточную переменную, которая содержит всю структуру, и удалить ее из этого:

let x = Box::new(("slefj".to_string(), "a".to_string()));
let pair = *x;
let (a, b) = pair;

Второй пример:

let pair = *x;
match pair {
    Tree::Pair(a, b) => Tree::Pair(a, b),
    _ => Tree::Nil,
};

Хорошей новостью является то, что ваш исходный код будет работать как есть, если по умолчанию включены нелексические времена жизни:

#![feature(nll)]

fn main() {
    let x = Box::new(("slefj".to_string(), "a".to_string()));
    let (a, b) = *x;
}

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

Другие вопросы по тегам