#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 _
в aamp;_
или преобразование простой ссылки в ссылку на объект признака). Таким образом, компилятор выбирает повторное заимствование значения, а не перемещение.
Например, этот код абсолютно корректен:
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; Где еще я должен был бы ожидать неперехода (например, копии какого-либо типа), если это подходит компилятору? Это не заставляет меня чувствовать себя уверенно. Но я приму ваш ответ, если так оно и есть.