Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ch13: Clarify closure capture types #3911

Closed
wants to merge 1 commit into from

Conversation

LukeFranceschini
Copy link
Contributor

Most places in this chapter are explicit about what type of capture is occurring ((im)mutable reference or ownership), and this change updates two more places to follow that standard. I've left the type of capture unspecified in the description of listing 13-16 because it is just a brief overview, and the capture type is now in the full breakdown immediately after the listing.

Most places in this chapter are explicit about what type of capture is
occurring ((im)mutable reference or ownership), and this change updates
two more places to follow that standard. I've left the type of capture
unspecified in the description of listing 13-16 because it is just a
brief overview, and the capture type is now in the full breakdown
immediately after the listing.
Copy link
Contributor

@chriskrycho chriskrycho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestions. I am going to close this, however:

  • In the first case, you are correct… but it is also covered repeatedly by the prose and the code sample, just not in that exact spot! 😅

  • In the second case, it actually does not capture a reference. Notice that the comparison is directly to s.size, another u32, and that there is no referencing (&shoe_size) or dereferencing (*shoe_size) happening. This works because u32 implements Copy, so there is no issue with the ownership.

Thanks!

@chriskrycho chriskrycho closed this May 9, 2024
@LukeFranceschini
Copy link
Contributor Author

Thanks for taking a look, I appreciate the explanation!
I just want to clarify something, if you don't mind, because I'm not sure I'm understanding why the shoe_size wouldn't be captured by reference. It seems like an immutable reference would be the least amount of access needed so that would be what gets used, like how it's described in part of section 13.1: Capturing References or Moving Ownership. I decided to try out the following, which I think would work if shoe_size was copied instead of captured as a reference:

let mut shoe_size: u32 = 9;
let shoe = Shoe { size: 7, style: String::from("sandal") };

let f = |s: &Shoe| s.size == shoe_size;

let shoe_size_ref_mut = &mut shoe_size;
f(&shoe);

but I get the following error when I try to do so:

error[E0502]: cannot borrow `shoe_size` as mutable because it is also borrowed as immutable
  --> src/shoe.rs:13:29
   |
11 |     let f = |s: &Shoe| s.size == shoe_size;
   |             ----------           --------- first borrow occurs due to use of `shoe_size` in closure
   |             |
   |             immutable borrow occurs here
12 |
13 |     let shoe_size_ref_mut = &mut shoe_size;
   |                             ^^^^^^^^^^^^^^ mutable borrow occurs here
14 |     f(&shoe);
   |     - immutable borrow later used here

For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` (bin "playground") due to 1 previous error

I ended up taking a look at the reference, and this section gave me a bit more confidence in my understanding of it:
https://doc.rust-lang.org/reference/types/closure.html#capture-modes

The compiler prefers to capture a closed-over variable by immutable borrow, followed by unique immutable borrow (see below), by mutable borrow, and finally by move. It will pick the first choice of these that is compatible with how the captured variable is used inside the closure body. [...]
If the move keyword is used, then all captures are by move or, for Copy types, by copy, regardless of whether a borrow would work.

So I think that if move had been used then shoe_size would have been copied as you said. Or if all of the borrows weren't compatible with how it was used in the closure then it would also be moved.

It's also very possible I'm misunderstanding something about the borrow checker. If so then my apologies and please let me know if that's the case! 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants