Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a File need to be mutable to call Read::read_to_string?

Here's a line from the 2nd edition Rust tutorial:

let mut f = File::open(filename).expect("file not found");

I'm of the assumption that the file descriptor is a wrapper around a number that basically doesn't change and is read-only.

The compiler complains that the file cannot be borrowed mutably, and I'm assuming it's because the method read_to_string takes the instance as the self argument as mutable, but the question is "why"? What is ever going to change about the file descriptor? Is it keeping track of the cursor location or something?

error[E0596]: cannot borrow immutable local variable `fdesc` as mutable
  --> main.rs:13:5
   |
11 |     let fdesc = File::open(fname).expect("file not found");
   |         ----- consider changing this to `mut fdesc`
12 |     let mut fdata = String::new();
13 |     fdesc.read_to_string(&mut fdata)
   |     ^^^^^ cannot borrow mutably

The whole source:

fn main() {
    let args: Vec<String> = env::args().collect();
    let query = &args[1];
    let fname = &args[2];
    println!("Searching for '{}' in file '{}'...", query, fname);

    let fdesc = File::open(fname).expect("file not found"); //not mut
    let mut fdata = String::new();
    fdesc.read_to_string(&mut fdata)
        .expect("something went wrong reading the file");

    println!("Found: \n{}", fdata);
}
like image 641
James M. Lay Avatar asked Dec 05 '17 19:12

James M. Lay


1 Answers

I'm assuming it's because the method read_to_string takes the instance as the self argument as mutable

Yes, that's correct:

fn read_to_string(&mut self, buf: &mut String) -> Result<usize>

The trait method Read::read_to_string takes the receiver as a mutable reference because in general, that's what is needed to implement "reading" from something. You are going to change a buffer or an offset or something.

Yes, an actual File may simply contain an underlying file descriptor (e.g. on Linux or macOS) or a handle (e.g. Windows). In these cases, the operating system deals with synchronizing the access across threads. That's not even guaranteed though — it depends on the platform. Something like Redox might actually have a mutable reference in its implementation of File.

If the Read trait didn't accept a &mut self, then types like BufReader would have to use things like internal mutability, reducing the usefulness of Rust's references.

See also:

  • Why is it possible to implement Read on an immutable reference to File?
like image 104
Shepmaster Avatar answered Sep 19 '22 14:09

Shepmaster