Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

write! macro does not compile in a separate method when taking reference

This is my code:

use std::fs::File;
use std::io::Write;

fn main() {
    let f = File::create("").unwrap();

    // Compiles
    write!(&f, "hi").unwrap();

    write_hi(&f);
}

fn write_hi(f: &File) {
    // Doesn't compile (cannot borrow `f` as mutable, as it is not declared as mutable)
    write!(f, "hi").unwrap();
}

When I have this line without the file being a parameter value, it compiles:

write!(&f, "hi").unwrap();

However, when the f is a parameter value, I get a compile error. It works when I make some mutability changes in the declaration of the f variable and method parameter, but isn't that odd?

Why doesn't the write! macro work on a non-mutable reference when it is used as a parameter value, like it does compile when the referencing variable is declared in the same method?

like image 546
J. Doe Avatar asked Dec 03 '20 23:12

J. Doe


1 Answers

The write! macro internally uses write_fmt which takes a &mut self. Your write!(&f, ...) is actually the odd one since the object being written to should be mutable, however you have an immutable File.

How does this work then? Write has an additional implementation for &Files. So you can write to a mutable reference to an immutable file. I'm not positive, but I believe this was added as a deliberate workaround to allow Files to be written to immutably.

It works in the first case because &f creates a temporary, which can be used mutably. The reason why write!(f, ... (with f being &File) doesn't work is because f is a variable that write_fmt wants to modify, so it needs to be mut.

fn write_hi(mut f: &File) {
         // ^^^
    write!(f, "hi").unwrap();
}

See also:

  • Why is it possible to implement Read on an immutable reference to File?
like image 140
kmdreko Avatar answered Feb 02 '23 21:02

kmdreko