Почему я не могу заимствовать переменную как изменяемую более одного раза одновременно с & mut Box <T>, пока работает & mut T? - PullRequest
0 голосов
/ 08 мая 2018

Я пытаюсь реализовать связанный список в Rust, и у меня возникают проблемы с пониманием разницы между этими двумя функциями:

enum List<T> {
    Nil,
    Cons(T, Box<List<T>>)
}

fn foo<T>(list: &mut Box<List<T>>) {
    match **list {
        List::Nil => return,
        List::Cons(ref mut head, ref mut tail) => {
            // ...
        }
    }
}

fn bar<T>(list: &mut List<T>) {
    match *list {
        List::Nil => return,
        List::Cons(ref mut head, ref mut tail) => {
            // ...
        }
    }
}

foo не скомпилируется со следующей ошибкой:

error[E0499]: cannot borrow `list` (via `list.1`) as mutable more than once at a time
  --> src/main.rs:66:34
   |
66 |         List::Cons(ref mut head, ref mut rest) => {
   |                    ------------  ^^^^^^^^^^^^ second mutable borrow occurs here (via `list.1`)
   |                    |
   |                    first mutable borrow occurs here (via `list.0`)
...
69 |     }
   |     - first borrow ends here

Однако, bar компилируется и работает отлично. Почему bar работает, а не foo? Я использую Rust версии 1.25.

1 Ответ

0 голосов
/ 08 мая 2018

Это можно упростить до

fn foo(v: &mut Box<(i32, i32)>) {
    match **v {
        (ref mut head, ref mut tail) => {}
    }
}

или

fn foo(v: &mut Box<(i32, i32)>) {
    let (ref mut head, ref mut tail) = **v;
}

Проблема в том, что Box - странный промежуточный тип.

В истории Rust Box был специально создан компилятором; он знал множество деталей Box, но это означало, что это было «волшебство», и никто другой не мог реализовать то, что работало как Box.

RFC 130 предложил изменить это; делая Box "просто другой тип". К сожалению, это все еще не было полностью передано.

Детали нюансы, но в основном текущая проверка заимствования обрабатывает сопоставление с шаблоном синтаксически , а не семантически . Это необходимо сделать, чтобы предотвратить некоторые проблемы со здоровьем.

В будущем нелексические времена жизни (NLL) просто волшебным образом исправят это; тебе не нужно ни к чему (ура!).

До этого вы можете явно вернуться к &mut T с помощью этого уродливого блоба:

match *&mut **list {

Или позвоните DerefMut явно:

match *std::ops::DerefMut::deref_mut(list) {

Однако есть очень мало причин для принятия &mut Box<T>.

Смотри также:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...