Подтвердить что ты не робот

Переменная привязка: перемещение & mut или заимствование референта?

Этот код выходит из строя, как ожидалось, в let c = a; с ошибкой компиляции "использование перемещенного значения: a":

fn main() {
    let a: &mut i32 = &mut 0;
    let b = a;
    let c = a;
}

a перемещается в b и больше не доступен для назначения c. Пока что так хорошо.

Однако, если я просто комментирую тип b и оставляю все остальное в покое:

fn main() {
    let a: &mut i32 = &mut 0;
    let b: &mut i32 = a;
    let c = a;
}

код снова сработает при let c = a;

Но на этот раз с очень другим сообщением об ошибке: "не может выйти из a, потому что он заимствован... Заем *a встречается здесь: let b: &mut i32 = a;"

Итак, если я просто комментирую тип b: нет перемещения a в b, но вместо этого "re" -borrow *a?

Что мне не хватает?

Приветствия.

4b9b3361

Ответ 1

Итак, если я просто комментирую b, введите: no move a в b, но вместо этого "re" -borrow *a?

Что мне не хватает?

Абсолютно ничего, поскольку в этом случае эти две операции семантически очень похожи (и эквивалентны, если a и b принадлежат к одной и той же области).

  • Либо вы перемещаете ссылку a в b, делая a перемещенное значение и больше не доступно.
  • Либо вы перебросите *a в b, сделав a непригодным для использования, пока b находится в области.

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

Этот пример не будет компилироваться, потому что a перемещается:

fn main() {
    let a: &mut i32 = &mut 0;
    { let b = a; }
    let c = a;
}

Но это будет, потому что когда b выходит за рамки a, разблокируется:

fn main() {
    let a: &mut i32 = &mut 0;
    { let b = &mut *a; }
    let c = a;
}

Теперь, на вопрос "Почему аннотирование типа b меняет поведение?", я предполагал бы следующее:

  • Когда нет аннотации типа, операция представляет собой простой и простой ход. Ничего не нужно проверять.
  • Когда есть аннотация типа, может потребоваться преобразование (перевод &mut _ в &_ или преобразование простой ссылки в ссылку на объект-объект). Поэтому компилятор выбирает повторное заимствование значения, а не движение.

Например, этот код является правдоподобным:

fn main() {
    let a: &mut i32 = &mut 0;
    let b: &i32 = a;
}

и здесь перемещение a в b не имеет никакого смысла, поскольку они имеют разный тип. Тем не менее этот код компилируется: b просто забирает *a, и значение не будет доступно с возможностью изменения через a, пока b находится в области.