#[Multithreading] Simple code not compiling

6 messages · Page 1 of 1 (latest)

proper bronze
#

This code does not compile for me and the error message isn't too helpful.

use std::thread;

fn main() {
    let example = "abc\ndegf\nghijkl".to_string();

    let mut handles = vec![];
    for line in example.lines() {
        handles.push(thread::spawn(move || {
            return line.len();
        }));
    }
    for handle in handles {
        let length = handle.join().unwrap();
        println!("Length: {}", length);
    }
}

Compiler Error:

error[E0597]: `example` does not live long enough
  --> src/main.rs:7:17
   |
7  |       for line in example.lines() {
   |                   ^^^^^^^^^^^^^^^ borrowed value does not live long enough
8  |           handles.push(thread::spawn(move || {
   |  ______________________-
9  | |             return line.len();
10 | |         }));
   | |__________- argument requires that `example` is borrowed for `'static`
...
16 |   }
   |    - `example` dropped here while still borrowed

For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground` due to previous error

If I remove to_string it compiles and gives the expected result, I guess because then it's a string slice with static lifetime.

But even though I'm using a String above, I'm making sure to join all threads before main returns. So how can I show the compiler that the string lives long enough?

knotty thistle
#

you can use scoped threads

high iris
#

Regardless whether example is a &str or String, .lines() is an iterator that produces &str values. In other words, in the for loop, each line is a &str. When you move the line into the thread, the compiler must ensure that the original data exists as long as the thread(s) exist. But because example is owned in the main thread, and becomes dropped, the compiler cannot ensure that requirement. (and my understanding is that the compiler isn't smart enough to know what you're joining all of the thread handles before example is dropped)

One simple fix would be to create an owned value that you then move into the created thread.

#

?play

use std::thread;

fn main() {
    let example = "abc\ndegf\nghijkl".to_string();

    let mut handles = vec![];
    for line in example.lines() {
        let line = line.to_owned();
        handles.push(thread::spawn(move || {
            return line.len();
        }));
    }
    for handle in handles {
        let length = handle.join().unwrap();
        println!("Length: {}", length);
    }
}
olive scaffoldBOT
#
     Running `target/debug/playground`

Length: 3
Length: 4
Length: 6