Home > Software design >  What's the proper way to use variables defined in the main thread in a child thread in Rust?
What's the proper way to use variables defined in the main thread in a child thread in Rust?

Time:11-27

I'm new to Rust and still reading the Rust book. Below is my program.

use clap::{App, Arg};

type GenericError = Box<dyn std::error::Error   Send   Sync   'static>;
type GenericResult<T> = Result<T, GenericError>;

fn main() -> GenericResult<()> {
    let matches = App::new("test")
        .arg(Arg::new("latency")
            .takes_value(true))
        .get_matches();


    let latency_present = matches.is_present("latency");
    let latency = matches.value_of("latency").unwrap_or("1000:10,300:30");
    let latency_pairs: Vec<&str> = latency.split(",").collect();

    let checker = std::thread::spawn(move || -> GenericResult<()>{
        loop {
            if latency_present {
                for (i, latency_pair) in latency_pairs.iter().enumerate() {
                    // let latency_pair: Vec<&str> = latency_pair.split(":").collect();
                    // let latency = latency_pair[0].parse::<f64>().unwrap();
                }
            }
        }
    });

    checker.join().unwrap()?;
    Ok(())
}

When I run it, it tells me this:

error[E0597]: `matches` does not live long enough
  --> src\main.rs:14:19
   |
14 |     let latency = matches.value_of("latency").unwrap_or("1000:10,300:30");
   |                   ^^^^^^^--------------------
   |                   |
   |                   borrowed value does not live long enough
   |                   argument requires that `matches` is borrowed for `'static`
...
30 | }
   | - `matches` dropped here while still borrowed

I don't quite understand the error messages here. But I guess it's because I use latency_pairs in the checker thread and latency_pairs could get dropped while checker is still executing. Is my understanding correct? How to fix the error? I tried for (i, latency_pair) in latency_pairs.clone().iter().enumerate() { in order to pass a cloned value for the thread, but it doesn't help.

CodePudding user response:

latency_pairs holds references into latency which in turn references matches. Thus cloning latency_pairs just clones the references into latency and matches.

Your code would require that latency's type is &'static str but it's actually &'a str where 'a is bound to matches' lifetime.

You can call to_owned() on latency to get an owned value and split the string inside the closure or you can call to_owned() on each of the splits collected in latency_pairs and move that Vec<String> into the closure:

    let latency_pairs: Vec<String> = latency.split(",").map(ToOwned::to_owned).collect();

    let checker = std::thread::spawn(move || -> GenericResult<()>{
        loop {
            if latency_present {
                for (i, latency_pair) in latency_pairs.iter().enumerate() {
                    // let latency_pair: Vec<&str> = latency_pair.split(":").collect();
                    // let latency = latency_pair[0].parse::<f64>().unwrap();
                }
            }
        }
    });

If you need to use latency_pairs outside of the closure, you can clone it before moving it into the closure:

    let latency_pairs: Vec<String> = latency.split(",").map(ToOwned::to_owned).collect();
    let latency_pairs_ = latency_pairs.clone();
    let checker = std::thread::spawn(move || -> GenericResult<()>{
        loop {
            if latency_present {
                for (i, latency_pair) in latency_pairs_.iter().enumerate() {
                    // let latency_pair: Vec<&str> = latency_pair.split(":").collect();
                    // let latency = latency_pair[0].parse::<f64>().unwrap();
                }
            }
        }
    });
    println!("{:?}", latency_pairs);
  • Related