Skip to content

Commit e3b34d0

Browse files
committed
Add example of error E0373 from not using move keyword in front of closure
1 parent 498c73b commit e3b34d0

File tree

2 files changed

+94
-5
lines changed

2 files changed

+94
-5
lines changed

documentation2/B09-Thread.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,94 @@ cargo run
244244
```bash
245245
Hello, World!
246246
```
247+
248+
Here, the closure `||` passed to the `thread::spawn()` function uses the `move` keyword to indicate that it takes ownership of the `message` variable.
249+
250+
When a value is moved into a thread, ownership of the value is transferred to the thread, and the main thread can no longer access the value.
251+
252+
This means that the closure can use the `message` variable even after the main thread has completed.
253+
254+
Let's look at what happens if we don't use the `move` keyword in front of the closure.
255+
256+
```rust
257+
use std::thread;
258+
259+
fn main() {
260+
let message = String::from("Hello, World!");
261+
262+
// using the message variable without a move
263+
let handle = thread::spawn(|| {
264+
println!("{}", message);
265+
});
266+
267+
handle.join().unwrap();
268+
}
269+
```
270+
271+
```bash
272+
cargo build
273+
```
274+
275+
#### Output
276+
277+
##### Output from Programiz Tutorial
278+
279+
```bash
280+
error[E0373]: closure may outlive the current function, but it borrows `message`, which is owned by the current function
281+
--> src/main.rs:7:32
282+
|
283+
7 | let handle = thread::spawn(|| {
284+
| ^^ may outlive borrowed value `message`
285+
8 | println!("{}", message);
286+
| ------- `message` is borrowed here
287+
|
288+
```
289+
290+
##### cargo build command and Output from code
291+
292+
```bash
293+
cargo build
294+
Compiling hello_world v0.1.0 (path_to_hello_world)
295+
error[E0373]: closure may outlive the current function, but it borrows `message`, which is owned by the current function
296+
--> src/main.rs:7:32
297+
|
298+
7 | let handle = thread::spawn(|| {
299+
| ^^ may outlive borrowed value `message`
300+
8 | println!("{}", message);
301+
| ------- `message` is borrowed here
302+
|
303+
note: function requires argument type to outlive `'static`
304+
--> src/main.rs:7:18
305+
|
306+
7 | let handle = thread::spawn(|| {
307+
| __________________^
308+
8 | | println!("{}", message);
309+
9 | | });
310+
| |______^
311+
help: to force the closure to take ownership of `message` (and any other referenced variables), use the `move` keyword
312+
|
313+
7 | let handle = thread::spawn(move || {
314+
| ++++
315+
316+
For more information about this error, try `rustc --explain E0373`.
317+
error: could not compile `hello_world` (bin "hello_world") due to 1 previous error
318+
```
319+
320+
____
321+
322+
The program in this case fails to compile. Here, Rust will try to borrow the message variable into the separate thread.
323+
324+
```bash
325+
7 | let handle = thread::spawn(|| {
326+
| ^^ may outlive borrowed value `message`
327+
```
328+
329+
However, Rust doesn't know how long the spawned thread will run. Thus it can't tell if the reference to the `message` variable will always be valid.
330+
331+
By adding the `move` keyword before the closure, we force the closure to take ownership of the `message` variable or any variable used inside closure.
332+
333+
We are telling Rust that the main thread won't use the `message` variable anymore. This is a classic example of Rust ownership and how it saves us from mishaps. To learn more about ownership in Rust, visit [Rust Ownership](https://www.programiz.com/rust/ownership).
334+
335+
Note that moving a value into a thread can be useful for parallelism, but it can also be a source of bugs if not used carefully.
336+
337+
____
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
use std::thread;
22

33
fn main() {
4-
// main thread starts here
54
let message = String::from("Hello, World!");
65

7-
// move the message value to a separate thread
8-
let handle = thread::spawn(move || {
6+
// using the message variable without a move
7+
let handle = thread::spawn(|| {
98
println!("{}", message);
109
});
1110

12-
// wait for the thread to finish
1311
handle.join().unwrap();
14-
}
12+
}

0 commit comments

Comments
 (0)