Christopher Reid
Christopher Reid

Reputation: 4482

passing external value to closure... error: capture of moved value

I read a file given as an argument, but when I try to pass it to handle_client in a task at the bottom so that it can be written to the tcp stream when someone connects I get error: capture of moved value: html... what am I missing?

fn get_file_string(path_str: &String) -> String{
    let path = Path::new(path_str.as_bytes());
    let file = File::open(&path);
    let mut reader = BufferedReader::new(file);
    reader.read_to_string().unwrap()
}

fn main() {

    let listener = TcpListener::bind("127.0.0.1:8001");
    let mut acceptor = listener.listen();

    let ref file_to_host = os::args()[1];
    let html = get_file_string(file_to_host).clone();

    fn handle_client(mut stream: TcpStream, html: String) {
        let write = stream.write_str(html.as_slice());
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("{}", e) }
            Ok(stream) => spawn(proc() {
                handle_client(stream,html)
            })
        }
    }
}

Upvotes: 1

Views: 1462

Answers (1)

Chris Morgan
Chris Morgan

Reputation: 90882

html is a String. Just like everything in Rust, a String is owned in exactly one place (if it satisfied Copy, it would be able to just duplicate it implicitly, but as it involves a heap allocation it’s definitely not). At present, you’re passing html to the handle_client function by value; therefore, when you call handle_client(stream, html), both stream and html are moved into that function and are no longer accessible. In the case of stream, that doesn’t matter as it’s a variable from inside the loop, but html comes from outside the loop; if it let you do it, it would take it the first time and work fine, but then it would be freed; second time through the loop, you would have an invalid String being passed through.

The solution in this case, seeing as you’re passing it through spawn and so can’t pass a reference (the slice, &str) is to clone the value so that that value can be moved into the proc and into the handle_client call:

Ok(stream) => {
    let html = html.clone();
    spawn(proc() {
        handle_client(stream, html)
    })
}

Upvotes: 6

Related Questions