Почему изменяемая ссылка не перемещена сюда?

У меня сложилось впечатление, что изменчивые ссылки (т.е. &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 к владению.

Если я немного подправлю общий, он тоже не будет жаловаться

      fn make_move_gen<T>(_: &mut T) {
}

или же

      let _ = *r_original; 
Другие вопросы по тегам