cognitive-engineering-lab / rust-book

The Rust Programming Language: Experimental Edition
https://rust-book.cs.brown.edu
Other
503 stars 82 forks source link

Confusing example of FnOnce vs FnMut #179

Open seishun opened 2 months ago

seishun commented 2 months ago

URL to the section(s) of the book with this problem: https://rust-book.cs.brown.edu/ch13-01-closures.html#moving-captured-values-out-of-closures-and-the-fn-traits

Description of the problem:

The FnMut trait is described as follows:

FnMut applies to closures that don’t move captured values out of their body, but that might mutate the captured values. These closures can be called more than once.

This conflicts with a later statement about the closure in Listing 13-8:

In contrast, Listing 13-8 shows an example of a closure that implements just the FnOnce trait, because it moves a value out of the environment.

Moving a value out of one's body is not the same as moving a value out of the environment. For example, this works:

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

fn main() {
    let mut list = [
        Rectangle { width: 10, height: 1 },
        Rectangle { width: 3, height: 5 },
        Rectangle { width: 7, height: 12 },
    ];

    let mut sort_operations = vec![];

    list.sort_by_key(move |r| {
        sort_operations.push(String::from("by key called"));
        r.width
    });
    println!("{:#?}", list);
}

Suggested fix:

Ideally, make the distinction between the two clear.

willcrichton commented 1 week ago

The "environment" is a general term that here includes all the variables in the defining scope of the closure. It doesn't just mean "top-level static variables". Is that the distinction you're getting at?

seishun commented 6 days ago

I don't follow. The error message further down says "cannot move out of value, a captured variable in an FnMut closure". I suppose the term "environment" could include captured variables, but that's too broad: you can move a value out of the environment in an FnMut closure as the example I provided earlier demonstrates.