Search code examples
rusthyper

How to re-use a value from the outer scope inside a closure in Rust?


I am trying to add a webserver (hyper) in a small Rust program and I'm getting hit with a move issue.

//main.rs

    // Suppose this is something meaningful and used in multiple places inside `main`
    let test: String = "Foo".to_string();

// ...

// This comes from here: https://docs.rs/hyper/0.14.8/hyper/service/fn.service_fn.html
// Determines what the web server sends back

    let make_svc = make_service_fn(|_conn| async {
        Ok::<_, Infallible>(service_fn(|req: Request<Body>| async move {
            // I need to somehow read the value of `test` here as well
            if req.version() == Version::HTTP_11 {
                Ok(Response::new(Body::from(test)))
            } else {
                Err("not HTTP/1.1, abort connection")
            }
        }))
    });

This produces the following issue:

The error

I understand that String can't have the Copy trait (and eventually I will need to use other more complex types). Essentially, I want to borrow or use a clone of the variable, because the variables will also be used outside of hyper's handler (for example, it could log to a file or be used for aggregate statistics over time).

So my question is, how does it work? How do I need to refactor the closure like so that I can somehow access the values of variables defined (and otherwise used) inside main?


Solution

  • If you want to clone test then you need to clone it outside the closure and then move it into the closure. Note that if you want to change test later on and have these changes reflected inside the closure you will need to use Arc<RefCell> so that both inside and outside the closure have mutable access to the same string.

    fn main() {
        let mut test: String = "Foo".to_string();
    
        // Clone the string so you can use it in a closure.
        let test_for_closure = test.clone();
        let closure = || {
            println!("{}", test_for_closure);
        };
    
        // You can still use test outside the closure
        println!("{}", test); // prints "Foo"
        closure(); // prints "Foo"
    
        // But if test is changed, test_for_closure will not change
        test = "Other".to_string();
        println!("{}", test); // prints "Other"
        closure(); // prints "Foo"
    }
    
    

    Let me know if you need help on using Arc<RefCell> for shared mutable access to the same string.