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

Cub*_*bic 1 rust

因此,我已经看到了这个问题,问题解释了如何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(())
}
Run Code Online (Sandbox Code Playgroud)

我传递了&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(())
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

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

Joe*_*lay 7

serde_json::to_writer的第一个参数接受任何实现的类型Write这样的值之一是&File

这可能令人惊讶,但是的docs File明确声明对文件的引用的可变性与文件是否会更改无关:

需要注意的是,虽然读写方法需要&mut File,因为对接口ReadWrite,的持有人&File仍可以修改该文件,无论是通过采取的方法&File或通过检索底层操作系统对象,并修改文件的方式。此外,许多操作系统允许通过不同的进程同时修改文件。避免假设持有某个&File文件不会更改。

您可能会问-等一下,我认为采用的方法Write&mut self?他们做到了!但是在这种情况下,Write是为实现的&File,因此传递给Write它的类型有些混乱&mut &File(对不可变引用的可变引用)。

这就解释了为什么您的第二个示例无法编译-您需要能够对进行可变引用&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
Run Code Online (Sandbox Code Playgroud)

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