Почему изменяемая ссылка не перемещена сюда?
У меня сложилось впечатление, что изменчивые ссылки (т.е. &mut T
) всегда перемещены. Это имеет смысл, так как они обеспечивают эксклюзивный изменяемый доступ. В следующем фрагменте кода я назначаю изменяемую ссылку другой изменяемой ссылке, и оригинал перемещается. В результате я больше не могу использовать оригинал:
let mut value = 900;
let r_original = &mut value;
let r_new = r_original;
*r_original; // error: use of moved value *r_original
Если у меня есть такая функция:
fn make_move(_: &mut i32) {
}
и измените мой оригинальный пример, чтобы он выглядел так:
let mut value = 900;
let r_original = &mut value;
make_move(r_original);
*r_original; // no complain
Я ожидаю, что изменчивая ссылка r_original
перемещается, когда я вызываю функцию make_move
с этим. Однако этого не происходит. Я все еще могу использовать ссылку после звонка.
Если я использую универсальную функцию make_move_gen
:
fn make_move_gen<T>(_: T) {
}
и назовите это так:
let mut value = 900;
let r_original = &mut value;
make_move_gen(r_original);
*r_original; // error: use of moved value *r_original
Ссылка снова перемещается, и поэтому программа ведет себя так, как я ожидал. Почему ссылка не перемещается при вызове функции make_move
?
4 ответа
Там может быть хорошая причина для этого.
&mut T
на самом деле не тип: все заимствования параметризованы некоторым (потенциально невыразимым) временем жизни.
Когда кто-то пишет
fn move_try(val: &mut ()) {
{ let new = val; }
*val
}
fn main() {
move_try(&mut ());
}
вывод типа двигателя выводит typeof new == typeof val
, поэтому они разделяют первоначальное время жизни. Это означает заимствование у new
не заканчивается, пока не заимствует у val
делает.
Это означает, что это эквивалентно
fn move_try<'a>(val: &'a mut ()) {
{ let new: &'a mut _ = val; }
*val
}
fn main() {
move_try(&mut ());
}
Тем не менее, когда вы пишете
fn move_try(val: &mut ()) {
{ let new: &mut _ = val; }
*val
}
fn main() {
move_try(&mut ());
}
происходит приведение типа - то же самое, что позволяет отбрасывать изменчивость указателя. Это означает, что время жизни какое-то (на вид неопределенное) 'b < 'a
, Это включает в себя актерский состав и, следовательно, повторное заимствование, поэтому повторное заимствование может выпасть из области видимости.
Правило всегда повторного заимствования, вероятно, было бы лучше, но явное объявление не слишком проблематично.
Я спросил что-то в этом духе здесь.
Кажется, что в некоторых (многих?) Случаях вместо перемещения происходит повторное заимствование. Безопасность памяти не нарушается, остается только "перемещенное" значение. Я также не смог найти никаких документов по этому поведению.
@Levans открыл здесь проблему с github, хотя я не совсем уверен, что это всего лишь проблема с документами: надежный отказ от ссылки &mu кажется ключевым в подходе Rust к владению.
Это
implicit reborrow
. Эта тема плохо документирована .
На этот вопрос уже дан неплохой ответ:
Если я немного подправлю общий, он тоже не будет жаловаться
fn make_move_gen<T>(_: &mut T) {
}
или же
let _ = *r_original;