Привязка переменной: перемещение a

#rust

Вопрос:

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

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

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

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

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

код снова выходит из строя при let c = a;

Но на этот раз с совсем другим сообщением об ошибке: «не могу выйти a , потому что оно заимствовано … заимствование *a происходит здесь: let b: amp;mut i32 = a; »

Итак, если я просто аннотирую b тип: нет перемещения a в b , но вместо этого «повторно»заимствую *a ?

Что я упускаю?

Ваше здоровье.

Ответ №1:

Итак, если я просто аннотирую b тип: нет перемещения a в b , но вместо этого «повторно»заимствую *a ?

Что я упускаю?

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

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

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

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

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

Но этот будет, потому что, как только b выйдет за рамки a , будет разблокирован:

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

Теперь, отвечая на вопрос «Почему аннотирование типа b изменяет поведение ?», я бы предположил, что:

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

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

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

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

Комментарии:

1. Спасибо Левансу за ответ. Я на самом деле проверил вариант subscope раньше, чтобы убедиться, что заимствование *a действительно имело место. В конце концов, это могло быть просто ложное сообщение компилятора. Что касается вашего предположения, мне было бы очень неудобно, если бы в любое время, когда я использую аннотацию типа, мне пришлось бы быть готовым к какой-то странной переписке очевидного смысла: let a = b; всегда должно быть просто перемещение или копия, с аннотацией типа или без.

2. @dacker ну, имейте в виду, что такое поведение может быть достигнуто только с amp;mut помощью ссылок, и в этом случае повторное заимствование-это просто копия, которая соблюдает правила заимствования.

3. Но разве это не было важным моментом во всех документах, которые я читал до сих пор: amp;muts всегда перемещаются в этих случаях? ПРИМЕЧАНИЕ: то же самое поведение, что и выше, происходит и с назначениями для ввода аннотированных amp;muts.

4. Если вы не играете с вложенными областями, повторное заимствование или перемещение amp;mut ссылки фактически одно и то же, поэтому неудивительно, что документы на самом деле не делают различия. И что вы называете «тип с аннотациями и мутами» ?

5. пусть b: amp;mut i32; b=a; Где еще я должен был бы ожидать неперехода (например, копии какого-либо типа), если это подходит компилятору? Это не заставляет меня чувствовать себя уверенно. Но я приму ваш ответ, если так оно и есть.