Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

multithreading - Extend lifetime of a variable for thread

I am reading a string from a file, splitting it by lines into a vector and then I want to do something with the extracted lines in separate threads. Like this:

use std::fs::File;
use std::io::prelude::*;
use std::thread;
fn main() {
    match File::open("data") {
        Ok(mut result) => {
            let mut s = String::new();
            result.read_to_string(&mut s);
            let k : Vec<_> = s.split("
").collect();
            for line in k {
                thread::spawn(move || {
                    println!("nL: {:?}", line);
                });
            }

        }
        Err(err) => {
            println!("Error {:?}",err);
        }
    }
}

Of course this throws an error, because s will go out of scope before the threads are started:

s` does not live long enough
main.rs:9           let k : Vec<_> = s.split("
").collect();
                                     ^

What can I do now? I've tried many things like Box or Arc, but I couldn't get it working. I somehow need to create a copy of s which also lives in the threads. But how do I do that?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem, fundamentally, is that line is a borrowed slice into s. There's really nothing you can do here, since there's no way to guarantee that each line will not outlive s itself.

Also, just to be clear: there is absolutely no way in Rust to "extend the lifetime of a variable". It simply cannot be done.

The simplest way around this is to go from line being borrowed to owned. Like so:

use std::thread;
fn main() {
    let mut s: String = "One
Two
Three
".into();
    let k : Vec<String> = s.split("
").map(|s| s.into()).collect();
    for line in k {
        thread::spawn(move || {
            println!("nL: {:?}", line);
        });
    }
}

The .map(|s| s.into()) converts from &str to String. Since a String owns its contents, it can be safely moved into each thread's closure, and will live independently of the thread that created it.

Note: you could do this in nightly Rust using the new scoped thread API, but that is still unstable.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...