1
votes

I am trying to read the contents of files in a directory in parallel. I'm running into lifetime issues.

My code looks like this:

use std::io::fs;
use std::io;
use std::collections::HashMap;
use std::comm;
use std::io::File;

fn main() {
    let (tx, rx) = comm::channel(); // (Sender, Receiver)
 
    let paths = fs::readdir(&Path::new("resources/tests")).unwrap();
 
    for path in paths.iter() {
        let task_tx = tx.clone();
 
        spawn(proc() {
            match File::open(path).read_to_end() {
                Ok(data) => task_tx.send((path.filename_str().unwrap(), data)),
                Err(e) => fail!("Could not read one of the files! Error: {}", e)
            };
        });
    }
 
    let mut results = HashMap::new();
 
    for _ in range(0, paths.len()) {
        let (filename, data) = rx.recv();
 
        results.insert(filename, data);
    }
 
    println!("{}", results);
}

The compilation error I'm getting is:

error: paths does not live long enough

note: reference must be valid for the static lifetime...

note: ...but borrowed value is only valid for the block at 7:19

I also tried to use into_iter() (or move_iter() previously) in the loop without much success.

I'm suspecting it has to do with the spawned tasks remaining alive beyond the entire main() scope, but I don't know how I can fix this situation.

1

1 Answers

4
votes

The error message might be a bit confusing but what it's telling you is that you are trying to use a reference path inside of a task. Because spawn is using proc you can only use data that you can transfer ownership of to that task (Send kind).

To solve that you can do this (you could use a move_iter but then you can't access paths after the loop):

for path in paths.iter() {
    let task_tx = tx.clone();

    let p = path.clone();
    spawn(proc() {
        match File::open(&p).read_to_end() {

The second problem is that you are trying to send &str (filename) over a channel. Same as for tasks types used must be of kind Send:

    match File::open(&p).read_to_end() {
        Ok(data) => task_tx.send((p.filename_str().unwrap().to_string(), data)),
        Err(e) => fail!("Could not read one of the files! Error: {}", e)
    };