Closures can only be coerced to `fn` on a function, but not on main

Hi,

I am playing with rouille [1] and on his examples he can easily share any state between requests as moving a Send variable into the closure Request -> Response as [2]. Easy and works. My problem is when I try to refactoring the handling method Request->Response, compiler don't want to capture variables anymore.

use rouille::{Request, Response};
use std::sync::{Arc, RwLock};

fn main() {
    // works();
    donotwork();
}

fn works() {
    use rouille::Request;
    use rouille::Response;

    let mut state = Arc::new(RwLock::new(vec![]));

    rouille::start_server("0.0.0.0:7780", move |request| {
        let mut guard = state.write().unwrap();
        guard.push(1);
        Response::text(format!("count {}", guard.len()))
    });
}

fn donotwork() {
    use rouille::Request;
    use rouille::Response;

    let mut state = Arc::new(RwLock::new(vec![]));

    rouille::start_server("0.0.0.0:7780", handle(state));
}

fn handle(mut state: Arc<RwLock<Vec<i32>>>) -> fn(&Request) -> Response {
    move |request| {
        let mut guard = state.write().unwrap();
        guard.push(1);
        Response::text(format!("count {}", guard.len()))
    }
}

the error:

error[E0308]: mismatched types
  --> src/bin/test1.rs:29:5
   |
28 |   fn handle(mut state: Arc<RwLock<Vec<i32>>>) -> fn(&Request) -> Response {
   |                                                  ------------------------ expected `for<'a> fn(&'a Request) -> Response` because of return type
29 | /     move |request| {
30 | |         let mut guard = state.write().unwrap();
31 | |         guard.push(1);
32 | |         Response::text(format!("count {}", guard.len()))
33 | |     }
   | |_____^ expected fn pointer, found closure
   |
   = note: expected fn pointer `for<'a> fn(&'a Request) -> Response`
                 found closure `[closure@src/bin/test1.rs:29:5: 29:19]`
note: closures can only be coerced to `fn` types if they do not capture any variables
  --> src/bin/test1.rs:30:25
   |
30 |         let mut guard = state.write().unwrap();
   |                         ^^^^^ `state` captured here

[1] GitHub - tomaka/rouille: Web framework in Rust
[2] rouille/database.rs at master · tomaka/rouille · GitHub

This has nothing to do with main vs. non-main.

A closure that captures state can't be converted to a function pointer. Where would the captured data go?

You probably want to return impl FnMut(&Request) -> Response instead of fn(&Request) -> Response.

1 Like

Almost. FnMut don't work, Fn works!

fn handle(mut state: Arc<RwLock<Vec<i32>>>) -> impl Fn(&Request) -> Response {

I think I am comprehend what was the issue. start_server never said it wants a plain function, I read it wrong and assume it when extract the method.

Thanks!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.