Причина такого поведения несколько неуловима. При передаче общей ссылки в качестве параметра функции, Rust просто скопирует ссылку. Тип &T
равен Copy
для всех T
, поскольку нам разрешено иметь любое количество общих ссылок одновременно.
С другой стороны, изменяемые ссылки не являются Copy
, поскольку в любой момент времени может быть только один из них. В соответствии с обычной семантикой Rust для не Copy
типов это означает, что изменяемые ссылки должны перемещаться при передаче в качестве параметра. Итак, почему этот код работает?
fn foo(_: &mut i32) {}
fn main() {
let mut i = 42;
let r = &mut i;
foo(r);
foo(r);
}
Причина в том, что компилятор создает неявное перезагружение всякий раз, когда он присваивает переменную, которая явно объявлена как изменяемая ссылка, поэтому функциязвонки переводятся на foo(&mut *r)
. Это создает новый заем, который длится только на время вызова функции, и исходная ссылка r
становится доступной снова, как только заканчивается срок жизни перезагружения.
Однако неявные перезагружения генерируются только для переменных, которыеявно объявлены с изменяемым ссылочным типом. Если мы изменим определение foo()
выше на
fn foo<T>(_: T) {}
, код перестанет компилироваться. Теперь параметр foo()
больше не объявляется как изменяемая ссылка, поэтому компилятор не будет вводить неявное повторное заимствование и вместо этого перенесет владение r
в функцию при первом вызове, что приведет к ошибке во второмвызов функции.
То же самое происходит в вашем коде. Функция to_writer()
объявлена как
pub fn to_writer<W, T: ?Sized>(writer: W, value: &T) -> Result<()>
where
W: io::Write,
T: Serialize,
Поскольку аргумент writer
не объявлен как изменяемая ссылка, вам необходимо создать явное перезапись, чтобы избежать перемещения:
serde_json::to_writer(&mut *out, &1)?;
Альтернативное решение, которое вы дали в своем вопросе, также работает - функция write_wrapper()
получает явно объявленную изменяемую ссылку в качестве аргумента, поэтому вызовы этой функции вызывают неявные перезагружения.