3

I have a threading operation in Rust which requires the use of a variable passed as an argument to the function the threads are spawned within, however I am seeing the following compile time error:

   Compiling Test v0.0.1 (file:///Users/clarkj84/Desktop/RustTest)
main.rs:9:22: 9:35 error: captured variable `test` does not outlive the enclosing closure
main.rs:9         let handle = thread::spawn(move || {
                               ^~~~~~~~~~~~~
main.rs:7:20: 16:2 note: captured variable is valid for the anonymous lifetime #1 defined on the block at 7:19
main.rs:7 fn test(test: &str){
main.rs:8     for _x in 0..2 {
main.rs:9         let handle = thread::spawn(move || {
main.rs:10             for _y in 0..2 {
main.rs:11                 println!("{}", test);
main.rs:12             }
           ...
note: closure is valid for the static lifetime
error: aborting due to previous error
Could not compile `Test`.

To learn more, run the command again with --verbose.

This is my code implementation:

use std::thread;

fn main() {
    test("test");
}

fn test(test: &str){
    for _x in 0..2 {
        let handle = thread::spawn(move || {
            for _y in 0..2 {
                println!("{}", test);
            }
        });
    }    
}
oli_obk
  • 28,729
  • 6
  • 82
  • 98
Jacob Clark
  • 3,317
  • 5
  • 32
  • 61
  • [This answer](http://stackoverflow.com/questions/28654978/lifetime-troubles-sharing-references-between-threads/28661524#28661524) from Shepmaster might shed some clues on your issue. In short, there is no guarantee that your reference lives longer than the thread you spawn. Either pass by value or encapsulate the reference in `Arc`. – Matthieu M. Jun 23 '15 at 11:34
  • @MatthieuM. How do I go about passing by value? – Jacob Clark Jun 23 '15 at 11:36
  • You would need a `String`, created from `test` in the loop body (but outside the closure) so that each thread you spawn get its own. – Matthieu M. Jun 23 '15 at 11:41

1 Answers1

2

Checkout @Shepmaster's answer for an explanation. There are two solutions to your problem depending on your use-case.

If your use case is just string literals (of type &'static str) and not arbitrary strings that are created during the program's execution, you can modify your function's signature to

fn test(test: &'static str)

This will allow you to pass any string literal to this function and move the string literal to another thread.

If on the other hand you want to create new strings by e.g. taking them from program arguments or environment variables, then you can create one String object per thread and pass that.

use std::thread;
use std::env;

fn main() {
    test("test");
    test(std::env::var("HOME").unwrap()); // pass the current home-directory
}

fn test(test: &str) {
    for _x in 0..2 {
        let string_object = test.to_string();
        let handle = thread::spawn(move || {
            for _y in 0..2 {
                println!("{}", string_object);
            }
        });
    }    
}
Community
  • 1
  • 1
oli_obk
  • 28,729
  • 6
  • 82
  • 98