1

This code does not compile...

fn main() {
    let data = "hi".to_string();
    let wrap = &data;
    std::thread::spawn(move || println!("{}", wrap));
}

...because data doesn't live inside the spawned thread:

error[E0597]: `data` does not live long enough
 --> src/main.rs:3:16
  |
3 |     let wrap = &data;
  |                ^^^^^ borrowed value does not live long enough
4 |     std::thread::spawn(move || println!("{}", wrap));
  |     ------------------------------------------------ argument requires that `data` is borrowed for `'static`
5 | }
  | - `data` dropped here while still borrowed

Why doesn't Rust move data like it does wrap? Is there any way to force data to be moved along with with wrap?

My real code looks more like this. I accept a message, parse it, and then send it to a thread for processing.

struct Message {
    data: Vec<u8>,
}
let message = Message {
    data: "{\"name\":\"Rust\"}".to_string(),
};

#[derive(Deserialize)]
struct Parsed<'a> {
    name: &'a str,
}
let parsed: Parsed = serde_json::from_slice(&message.data).unwrap();

std::thread::Builder::new()
    .name(parsed.name) // note: need some of the parsed data prior to moving into the thread...so cannot solve with JSON parsing inside thread
    .spawn(move || println("{}", parsed.name));

I know I could modify my Parsed struct to use Strings instead of &'a str, but this reduces efficiency when the compiler should be able to move data just fine.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Chris Smith
  • 2,928
  • 4
  • 27
  • 59
  • It looks like your question might be answered by the answers of [Why can't I store a value and a reference to that value in the same struct?](https://stackoverflow.com/q/32300132/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Oct 13 '20 at 15:41
  • 1
    Does this answer your question? [Lifetime of references in closures](https://stackoverflow.com/questions/42747620/lifetime-of-references-in-closures) – trent Oct 13 '20 at 16:00
  • To rephrase my question: once I move a reference, I can never make use of the original even if I somehow move it along with the reference? – Chris Smith Oct 14 '20 at 01:26
  • That doesn't sound like a rephrasing of the same question. Moving `wrap` has no effect on what you can do with `data`. (Moving or mutating `data` would invalidate `wrap`, though.) The reason for the error message here is because `thread::spawn` requires all references to be `'static`. – trent Oct 14 '20 at 13:10

1 Answers1

7

Why doesn't Rust move data like it does wrap

Several reasons - take your pick:

  1. Because wrap is captured, not data, and the closure moves what is captured.

  2. Because the move of data would immediately invalidate both wrap itself and other references to data if they exist. Also, the enclosing scope might itself need data for further access.

  3. Because then there would be no way to have a closure that captures some values by move and some by reference. Currently you can make a closure move but still elect to capture certain values by reference simply by creating an explicit reference and capturing that. The feature you propose would make that impossible.

user4815162342
  • 141,790
  • 18
  • 296
  • 355