rust - 如何使用相同的可变借用两次调用 serde_json::to_writer?
问题描述
我正在尝试编写一个调用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(())
}
编辑:想出了一种方法来编译,但有没有更简单的方法(游乐场链接):
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();
}
解决方案
这种行为的原因有些微妙。当将共享引用作为参数传递给函数时,Rust 将简单地复制该引用。该类型&T
是Copy
for all T
,因为我们可以同时拥有任意数量的共享引用。
另一方面,可变引用不是Copy
,因为在任何给定时间只能有一个。根据非Copy
类型的常用 Rust 语义,这意味着可变引用在作为参数传递时应该被移动。那么为什么这段代码有效呢?
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) {}
代码将停止编译。现在参数 offoo()
不再声明为可变引用,因此编译器不会引入隐式重借,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()
函数接收显式声明的可变引用作为参数,因此对该函数的调用会触发隐式重借。
推荐阅读
- javascript - 我可以在我的 WebView 中注入哪些 JavaScript/CSS 来仅反转页面背景和白色文本?
- python - 如何在 Matplotlib 中填充该区域
- scala - Scala 模式匹配等式案例
- keras - Keras:如何检查输入层中预期的数据类型是什么?
- android - 如何获取下拉列表中的项目数?(自动完成文本视图)
- python - python处理来自url的传入
- google-cloud-firestore - Firebase 如何一次性检索文档集合以及每个文档的子集合?
- opengl - glbadcontext 的可能原因
- javascript - 通过迭代我需要使用 javascript 过滤特定的单词,但我没有得到预期的值?
- python - 按照 Django 教程,“python manage.py migrate”不会创建任何 django 表(MySQL、Pycharm)