It's difficult to make a mindset shift from javascript to rust :). In javascript, closures can share the context of a parent. I use this feature to create configured functions on the fly. I pass these configured closures/functions/promises to other structs and use them in loops. I can then just call the closure anywhere to dynamically retrieve a value. Achieving similar behavior in Rust always feels extremely painful :). Pins, boxes, arcs, etc.
Here's an example (using async-std again):
let users = Arc::new({
let mut users: HashMap<String, String> = HashMap::with_hasher(RandomState::new());
users.insert("John".to_string(), "John Smith".to_string());
users
});
let get_full_name = Box::pin(|name: String| async move {
let users = users.clone();
users.get(&name).unwrap().to_string()
});
loop {
let user = get_full_name("John".to_string()).await; // move occurs
println!("{}", user);
break;
}
What's the rust way to achieve this? So creating a resolver within a loop is not performant so I wanna create a configured resolver once and then call it on several places. It feels like such practice is not meant to be used in Rust. Am I right? What's the proper way?
Your example with users doesn't really need async/await. The body of your get_full_name doesn't have any .await, so it would be equivalent to an ordinary closure:
let get_full_name = |name: String| {
let users = users.clone();
users.get(&name).unwrap().to_string()
};
That said, your example is somewhat silly. How about getting the name directly?
loop {
let user = users.get("John").unwrap().to_string();
println!("{}", user);
}
True, I made a simple example using async because actual examples would be too long. So the example tries to present the problem I have. Let me try to better illustrate the use case:
...
loop {
let router = Router::new();
router.set_resolver(get_full_name); // => this function is called as `get_full_name("John")`
router.resolve().await;
}
So let say you have a crate which provides a Router. You can configure this object by passing configured resolvers that retrieve some data. How these data are resolved is the responsibility of a closure you pass to it. Makes sense?
I would not use a closure for this. If you have to give it a handle like that, consider giving it the sender of an oneshot channel and await the channel instead of (or after) the router.