-
Notifications
You must be signed in to change notification settings - Fork 144
Provide more information about disjoint capture in closures and migration instructions #246
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
Changes from 1 commit
cdd007f
c72d0bc
fb73551
6a236ad
513f357
16d12b4
ce4ffb3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,7 @@ | |
| ## Summary | ||
|
|
||
| - `|| a.x + 1` now captures only `a.x` instead of `a`. | ||
| - This can subtly change the drop order of things. | ||
| - This can subtly change the drop order of things, and auto traits usage with closures. | ||
|
|
||
| ## Details | ||
|
|
||
|
|
@@ -29,12 +29,71 @@ let c = || println!("{}", a.y); // Error: Tries to capture all of `a` | |
| c(); | ||
| ``` | ||
|
|
||
| Starting in Rust 2021, closures will only capture the fields that they use. | ||
| Starting in Rust 2021, closures will only capture the fields that they use, eliminating common borrow check errors. | ||
| So, the above example will compile fine in Rust 2021. | ||
|
|
||
| This new behavior is only activated in the new edition, | ||
| since it can change the order in which fields are dropped. | ||
| As for all edition changes, an automatic migration is available, | ||
| which will update your closures for which this matters. | ||
| It can insert `let _ = &a;` inside the closure to force the entire | ||
| struct to be captured as before. | ||
| Disjoint capture was proposed as part of [RFC 2229](https://github.com/rust-lang/rfcs/blob/master/text/2229-capture-disjoint-fields.md), and we suggest reading the RFC to better understand motivations behind the feature. | ||
|
|
||
| ## Changes to semantics because of disjoint capture | ||
| `#[feature(capture_disjoint_fields)]` introduces (minor) breaking change to the language. This means that there might be observable changes or valid Rust 2018 code that fails to compile once you move to Rust Edition 2021. You can use `cargo fix` with the `disjoint_capture_migrations` lint to migrate your existing code to Rust 2021. | ||
roxelo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ### Wild Card Patterns | ||
| Closures now only capture data that needs to be read, which means the following closures will not capture `x` | ||
|
|
||
| ```rust,ignore | ||
roxelo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| let x = 10; | ||
| let c = || { | ||
| let _ = x; | ||
| }; | ||
|
|
||
| let c = || match x { | ||
| _ => prinln!("Hello World!") | ||
roxelo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| }; | ||
| ``` | ||
|
|
||
| ### Drop Order | ||
| Since only a part of a variable might be captured instead of the entire variable, when different fields or elements (in case of tuple) get drop, the drop order might be affected. | ||
|
|
||
| ```rust,ignore | ||
| { | ||
| let t = (vec![0], vec![0]); | ||
|
|
||
| { | ||
| let c = || { | ||
| move(t.0); | ||
roxelo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| }; | ||
| } // c and t.0 dropped here | ||
| } // t.1 dropped here | ||
|
|
||
| ``` | ||
|
|
||
|
|
||
| ### Auto Traits | ||
| Structs or tuples that implement (an) auto trait(s) and are passed along in a closure may no longer guarantee that the closure can also implement that/those auto trait(s). | ||
roxelo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| For instance, a common way to allow passing around raw pointers between threads is to wrap them in a struct and then implement `Send`/`Sync` auto trait for the wrapper. The closure that is passed to `thread::spawn` uses the specific fields within the wrapper but the entire wrapper is captured regardless. Since the wrapper is `Send`/`Sync`, the code is considered safe and therefore compiles successfully. | ||
|
|
||
| With this feature only the specific field mentioned in the closure gets captured, which wasn't originally `Send`/`Sync` defeating the purpose of the wrapper. | ||
roxelo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
|
|
||
| ```rust,ignore | ||
| struct Ptr(*mut i32); | ||
| unsafe impl Send for Ptr; | ||
roxelo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
|
|
||
| let mut x = 5; | ||
| let px = (&mut x as *mut i32); | ||
roxelo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| let c = thread::spawn(move || { | ||
| *(px.0) += 10; | ||
| }); // Closure captured px.0 which is not Send | ||
| ``` | ||
|
|
||
|
||
| ## Migrations | ||
|
|
||
| This new behavior is only activated in the new edition, or by specifically enabling it using `#[feature(capture_disjoint_fields)]`, | ||
roxelo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| since it can change the order in which fields are dropped and can impact auto trait usage with closures. | ||
|
|
||
| As for all edition changes, an automatic migration is available. | ||
| If you would like to be warned of semantics change that may impact your code, you can [use the lint](https://doc.rust-lang.org/rustc/lints/levels.html) `disjoint_capture_migrations`. The lint is also supported with [cargo fix](https://doc.rust-lang.org/cargo/commands/cargo-fix.html) to automatically migrate your code. | ||
|
|
||
| The migration fix involves adding `let _ = &a;` inside the closure to force the entire variable to be captured as before. | ||
roxelo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
Uh oh!
There was an error while loading. Please reload this page.