这种行为的原因有些微妙。当将共享引用作为参数传递给函数时,Rust 将简单地复制该引用。方式&T
is 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()
函数接收显式声明的可变引用作为参数,因此调用此函数会触发隐式重新借用。