为什么serde_json :: to_writer不需要其参数为`mut`?

时间:2019-07-27 13:17:52

标签: rust

因此,我看过一个this问题,该问题解释了serde_json如何既可以通过引用获取读者/作家,也可以通过获取所有权来实现。足够公平。

但是我不知道该方法如何用于Write-所有Write方法都需要一个&mut self,所以我认为如果我通过只知道其方法的方法参数是对Write的引用,它对此无能为力。但是,即使我将非mut引用传递给以某种方式最终写入被引用文件的方法,该示例也可以编译并正常工作:

extern crate serde_json;

use std::fs::OpenOptions;
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let file = OpenOptions::new()
        .create(true)
        .write(true)
        .truncate(true)
        .open("/tmp/serde.json")?;
    // why does this work?
    serde_json::to_writer(&file, &10)?;
    Ok(())
}

我正在传递&File-如预期的那样,如果我要在Write上直接调用File的任何方法,将无法正常工作:

use std::io::{self, Write};
use std::fs::OpenOptions;

fn main() -> io::Result<()> {
    let file = OpenOptions::new()
        .create(true)
        .write(true)
        .truncate(true)
        .open("/tmp/wtf")?;
    let file_ref = &file;
    // this complains about not having a mutable ref as expected
    file_ref.write(&[1,2,3])?;
    Ok(())
}
error[E0596]: cannot borrow `file_ref` as mutable, as it is not declared as mutable
  --> test.rs:12:5
   |
10 |     let file_ref = &file;
   |         -------- help: consider changing this to be mutable: `mut file_ref`
11 |     // this complains about not having a mutable ref as expected
12 |     file_ref.write(&[1,2,3])?;
   |     ^^^^^^^^ cannot borrow as mutable

那有什么用呢? serde_json是否以某种方式破坏了类型系统,或者这是类型系统的故意特征?如果是后者,它如何工作以及为什么这样工作?

1 个答案:

答案 0 :(得分:5)

serde_json::to_writer的第一个参数接受实现Write的任何类型。 One such value is &File

这可能令人惊讶,但是File的文档明确声明了 reference 对文件的可变性与文件是否更改无关。

  

请注意,尽管读写方法需要&mut File,但是由于ReadWrite的接口,&File的持有者仍然可以修改文件,可以通过采用&File的方法,也可以通过检索基础OS对象并以此方式修改文件。此外,许多操作系统允许通过不同的进程同时修改文件。避免假定持有&File意味着文件不会更改。

您可能会问-等一下,我认为Write上的方法花费了&mut self?他们做到了!但是在这种情况下,Write是为&File实现的,因此传递给Write的类型在某种程度上令人困惑,是&mut &File(对不变引用的可变引用)。 / p>

这说明了为什么您的第二个示例无法编译-您需要能够对&file进行可变引用,并且在绑定可变之前就不能这样做。这是要实现的重要事情-绑定的可变性和绑定值的可变性不一定相同。

在运行代码时,错误消息中会对此进行提示:

error[E0596]: cannot borrow `file_ref` as mutable, as it is not declared as mutable
  --> src/lib.rs:11:5
   |
10 |     let file_ref = &file;
   |         -------- help: consider changing this to be mutable: `mut file_ref`
11 |     file_ref.write(&[1,2,3])?;
   |     ^^^^^^^^ cannot borrow as mutable

error: aborting due to previous error

如果将let file_ref = &file;更改为let mut file_ref = &file;,则会编译代码。