diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /src/doc/rust-by-example/src/fn/closures/capture.md | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/doc/rust-by-example/src/fn/closures/capture.md')
-rw-r--r-- | src/doc/rust-by-example/src/fn/closures/capture.md | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/src/doc/rust-by-example/src/fn/closures/capture.md b/src/doc/rust-by-example/src/fn/closures/capture.md new file mode 100644 index 000000000..061ef1c7b --- /dev/null +++ b/src/doc/rust-by-example/src/fn/closures/capture.md @@ -0,0 +1,115 @@ +# Capturing + +Closures are inherently flexible and will do what the functionality requires +to make the closure work without annotation. This allows capturing to +flexibly adapt to the use case, sometimes moving and sometimes borrowing. +Closures can capture variables: + +* by reference: `&T` +* by mutable reference: `&mut T` +* by value: `T` + +They preferentially capture variables by reference and only go lower when +required. + +```rust,editable +fn main() { + use std::mem; + + let color = String::from("green"); + + // A closure to print `color` which immediately borrows (`&`) `color` and + // stores the borrow and closure in the `print` variable. It will remain + // borrowed until `print` is used the last time. + // + // `println!` only requires arguments by immutable reference so it doesn't + // impose anything more restrictive. + let print = || println!("`color`: {}", color); + + // Call the closure using the borrow. + print(); + + // `color` can be borrowed immutably again, because the closure only holds + // an immutable reference to `color`. + let _reborrow = &color; + print(); + + // A move or reborrow is allowed after the final use of `print` + let _color_moved = color; + + + let mut count = 0; + // A closure to increment `count` could take either `&mut count` or `count` + // but `&mut count` is less restrictive so it takes that. Immediately + // borrows `count`. + // + // A `mut` is required on `inc` because a `&mut` is stored inside. Thus, + // calling the closure mutates the closure which requires a `mut`. + let mut inc = || { + count += 1; + println!("`count`: {}", count); + }; + + // Call the closure using a mutable borrow. + inc(); + + // The closure still mutably borrows `count` because it is called later. + // An attempt to reborrow will lead to an error. + // let _reborrow = &count; + // ^ TODO: try uncommenting this line. + inc(); + + // The closure no longer needs to borrow `&mut count`. Therefore, it is + // possible to reborrow without an error + let _count_reborrowed = &mut count; + + + // A non-copy type. + let movable = Box::new(3); + + // `mem::drop` requires `T` so this must take by value. A copy type + // would copy into the closure leaving the original untouched. + // A non-copy must move and so `movable` immediately moves into + // the closure. + let consume = || { + println!("`movable`: {:?}", movable); + mem::drop(movable); + }; + + // `consume` consumes the variable so this can only be called once. + consume(); + // consume(); + // ^ TODO: Try uncommenting this line. +} +``` + +Using `move` before vertical pipes forces closure +to take ownership of captured variables: + +```rust,editable +fn main() { + // `Vec` has non-copy semantics. + let haystack = vec![1, 2, 3]; + + let contains = move |needle| haystack.contains(needle); + + println!("{}", contains(&1)); + println!("{}", contains(&4)); + + // println!("There're {} elements in vec", haystack.len()); + // ^ Uncommenting above line will result in compile-time error + // because borrow checker doesn't allow re-using variable after it + // has been moved. + + // Removing `move` from closure's signature will cause closure + // to borrow _haystack_ variable immutably, hence _haystack_ is still + // available and uncommenting above line will not cause an error. +} +``` + +### See also: + +[`Box`][box] and [`std::mem::drop`][drop] + +[box]: ../../std/box.md +[drop]: https://doc.rust-lang.org/std/mem/fn.drop.html |