Why doesn't I need the `mut` keyword

I understand that in Rust, all variables are immutable by default.
Given the following structs and there implementations:

#[derive(Debug)]
struct PDFDocument {
    pages: Vec<PDFDocumentPage>,
}

impl Default for PDFDocument {
    fn default() -> Self {
        Self { pages: Vec::new() }
    }
}

impl PDFDocument {
    fn save(mut self) {
        println!("Saving PDF document...");

        if self.pages.is_empty() {
            self.pages.push(PDFDocumentPage::default())
        }
    }
}

#[derive(Debug)]
struct PDFDocumentPage {}

impl Default for PDFDocumentPage {
    fn default() -> Self {
        Self {}
    }
}

I try to use it in the main function:

fn main() {
    let document = PDFDocument::default();
    document.save();
}

Why don't I need the document variable to be marked as mut here?
Seems that I don't understand Rust :slight_smile:

1 Like

Because calling document.save() for fn save(mut self) moves document into save and when you move you are allowed to change mutability.

1 Like

That's a new insight for my, but if you think about it, it's obvious off course.
Thanks for the explanation.

1 Like

The way I think about this is that in

fn save(mut self) {
    // ...
}

the mut is not part of the function's signature, even though it sort of looks like it is. There is no difference between fn save(mut self) and fn save(self) in terms of how you're allowed to call the function (because that analysis is done on the basis of the signature only); the only difference is in what you're allowed to do with self in the body of the function.

2 Likes

Following that up a bit more, you can also do this:

impl PDFDocument {
    fn modify(&mut self) { /* ... */ }
}

fn main() {
    let document = PDFDocument::default();
    let mut document = document;
    document.modify();
}

So similarly you could have wrote

impl PDFDocument {
    fn save(self) {
        // (Different name because you can't shadow `self` specifically)
        let mut self_ = self;
        // ...
    }
}

So (a) changing mutability when moving is a general thing and not a function call specific thing, and (b) the signature doesn't even actually tell you if the argument is modified in the body or not.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.