如何使用相同的可变借用两次调用 serde_json::to_writer?

Kan*_*dan 5 rust

我正在尝试编写一个调用serde_json::to_writer两次的函数来写两件事,但我不知道怎么做。

这是一次尝试(游乐场链接):

extern crate serde_json;

fn main() {
    let mut out = std::fs::File::create("out.txt").unwrap();
    write_stuff(&mut out);
}

fn write_stuff<W: ?Sized>(out: &mut W) -> Result<(), std::io::Error>
where
    W: std::io::Write,
{
    serde_json::to_writer(out, &1).unwrap();  // `out`: value moved here
    serde_json::to_writer(out, &2).unwrap();  // `out`: value used here after move
    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

编辑:想出了一种方法来编译东西,但有没有更简单的方法(游乐场链接):

extern crate serde_json;

fn main() {
    let mut out = std::fs::File::create("out.txt").unwrap();
    write_stuff(&mut out);
}

fn write_stuff<W: ?Sized>(out: &mut W)
where
    W: std::io::Write,
{
    write_wrapper(out);
    write_wrapper(out);
}

fn write_wrapper<W: ?Sized>(out: &mut W)
where
    W: std::io::Write,
{
    serde_json::to_writer(out, &1).unwrap();  
}
Run Code Online (Sandbox Code Playgroud)

Sve*_*ach 3

这种行为的原因有些微妙。当将共享引用作为参数传递给函数时,Rust 将简单地复制该引用。该类型&T适用Copy于 all T,因为我们可以同时拥有任意数量的共享引用。

\n\n

另一方面,可变引用则不然Copy,因为在任何给定时间只能有其中一个。根据非Copy类型的通常 Rust 语义,这意味着可变引用在作为参数传递时应该被移动。那么为什么这段代码可以工作呢?

\n\n
fn foo(_: &mut i32) {}\n\nfn main() {\n    let mut i = 42;\n    let r = &mut i;\n    foo(r);\n    foo(r);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

原因是编译器每当分配给显式声明为可变引用的变量时都会创建隐式重借用,因此函数调用会转换为foo(&mut *r). 这将创建一个新的借用,该借用仅在函数调用期间持续,并且r一旦重新借用的生命周期结束,原始引用将再次可用。

\n\n

但是,仅针对使用可变引用类型显式声明的变量生成隐式重新借用。foo()如果我们将上面的定义改为

\n\n
fn foo<T>(_: T) {}\n
Run Code Online (Sandbox Code Playgroud)\n\n

代码将停止编译。现在 的参数foo()不再被声明为可变引用,因此编译器不会引入隐式重借,并且会移动 的所有权r在第一次调用时将 的所有权转移到函数中,从而导致第二次函数调用时出错。

\n\n

您的代码中也会发生同样的情况。该函数to_writer()声明为

\n\n
pub fn to_writer<W, T: ?Sized>(writer: W, value: &T) -> Result<()>\nwhere\n    W: io::Write,\n    T: Serialize,\n
Run Code Online (Sandbox Code Playgroud)\n\n

由于参数writer未声明为可变引用,因此您需要创建显式重新借用以避免移动:

\n\n
serde_json::to_writer(&mut *out, &1)?;\n
Run Code Online (Sandbox Code Playgroud)\n\n

您在问题中给出的替代解决方案也有效 \xe2\x80\x93 该write_wrapper()函数接收显式声明的可变引用作为参数,因此调用此函数会触发隐式重新借用。

\n