2015-08-22 5 views
7

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

Code example

+2

Явное создание экземпляра ('make_move :: <&mut i32> (r_original);') работает как исходная функция (без перемещения). Захватывающий; Я бы предположил, что проверка чека происходит до ввода типа. – Veedrac

+0

Ответ от dacker Я предполагаю, что это так: Явно аннотируя тип, который является изменчивой ссылкой, запускает повторное заимствование содержимого вместо перемещения, оставляя исходную ссылку снова полезной после новой ссылки (здесь, в области make_move) выходит за рамки. –

ответ

5

Возможно, для этого есть веская причина.

&mut T не Фактически a тип: все заимствования параметризуются некоторым (потенциально невыразимым) временем жизни.

Когда один пишет

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. Это включает в себя бросок и, следовательно, переборку, и поэтому перебор может выйти из сферы действия.

Правило всегда-reborrow, вероятно, будет приятнее, но явное объявление не является слишком проблематичным.

+0

Я так и не думал об этом. Однако это кажется логичным. Под «отличной изменчивостью указателя» вы подразумеваете получение общей ссылки из изменяемой ссылки? Например, пусть r: & i32 = r_mut; где r_mut is & mut i32. –

+0

"Поменяйте указатель изменчивость", вы имеете в виду "→ Yep. – Veedrac

+0

Хорошее объяснение. Это действительно имеет смысл. Мое предположение относительно '' b' было бы: это пересечение '' a', которое охватывает тело 'move_try' и вложенную область, в которой определяется' new'; поэтому '' b' будет этой вложенной областью, в конце которой заканчивается заимствование 'new'. – dacker

2

я спросил что-то вдоль этих линий here.

Кажется, что в некоторых (много?) Случаях вместо перемещения происходит повторное заимствование. Безопасность памяти не нарушена, только «перемещенное» значение все еще находится вокруг. Я тоже не мог найти никаких документов по этому поведению.

@ Levans открыла проблему github here, хотя я не совсем уверен, что это просто проблема с док-станцией: надежное перемещение из ссылки & кажется центральным для подхода Rust к владению.

Смежные вопросы