0

With the code:

use std::thread;

// result of expensive calculation
#[derive(Debug)]
pub struct Foo(String);

fn main() {
    let foo = Foo(String::from("expensive!"));
    let p = &foo;
    let q = &foo;
    
    let handle = thread::spawn(move || {
            println!("{:?} from the spawned thread!", q);
    });
    
    println!("{:?} from main thread", p);
    
    handle.join().unwrap();
}

I get the error:

error[E0597]: `foo` does not live long enough
  --> src/main.rs:10:13
   |
10 |       let q = &foo;
   |               ^^^^ borrowed value does not live long enough
11 |       
12 |       let handle = thread::spawn(move || {
   |  __________________-
13 | |             println!("{:?} from the spawned thread!", q);
14 | |     });
   | |______- argument requires that `foo` is borrowed for `'static`
...
19 |   }
   |   - `foo` dropped here while still borrowed

I believe that foo lives from its declaration until after handle.join().unwrap().

Am I correct, and if so, how can I convince the compiler of this?

fadedbee
  • 42,671
  • 44
  • 178
  • 308
  • 1
    I'll be surprised if you get an answer that's any more satisfying than that it's because nobody's thought of, and implemented, that particular optimization. I don't know much about rust, but I would not _assume_ that the compiler knows what `thread::spawn(...)` means or what `handle.join()` means beyond the fact that those are function calls. The error message has nothing to do with the _thread_, it's complaining about the lambda. – Solomon Slow Sep 17 '20 at 12:36
  • 3
    @SolomonSlow It's not a matter of optimizing, it's a matter of correctness. As you correctly point out, the compiler doesn't special-case `thread::spawn`, its _signature_ doesn't allow the closure to refer to anything other than static data. – user4815162342 Sep 17 '20 at 13:25
  • @user4815162342, Yes, I suppose you are right. I said "optimization," but maybe I should have said, "complication." You _could_ change the rules of the language to allow that particular program to compile—it's pretty obvious what the compiled code should do in that case—and the code in the compiler that could recognize the difference between that special case and other, more problematic cases would somewhat resemble an "optimizer." But yeah, Changing the language to make it legal would unnecessarily complicate both the language and the compiler. It's not legal, and it should stay that way. – Solomon Slow Sep 17 '20 at 13:45
  • 1
    @SolomonSlow *It's not legal, and it should stay that way* - I'm not so sure about that part. It would be nice if Rust allowed the signature to name the lifetime of the returned `JoinHandle` and specify that the references in the closure mustn't outlive it. That kind of thing might also be useful for async/await as well. – user4815162342 Sep 17 '20 at 14:28

0 Answers0