Hello,
I'm stuck on a little problem in rust, the code is this one :
let client = reqwest::ClientBuilder::new().redirect(redirect::Policy::none()).build().unwrap();
let mut bodies = stream::iter(urls)
.map(|url| async move { (client.get(&url).send().await, url) })
.buffer_unordered(workers);
And the error is this one :
error[E0507]: cannot move out of `client`, a captured variable in an `FnMut` closure
--> src/main.rs:541:31
|
539 | let client = reqwest::ClientBuilder::new().redirect(redirect::Policy::none()).build().unwrap();
| ------ captured outer variable
540 | let mut bodies = stream::iter(urls)
541 | .map(|url| async move { (client.get(&url).send().await, url) })
| ^^^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | move occurs because `client` has type `reqwest::async_impl::client::Client`, which does not implement the `Copy` trait
| | move occurs due to use in generator
| move out of `client` occurs here
I can't solve this issue, I have a lot of trouble with this closure borrowing thing...
Thank you
They are pretty much equivalent in this case. The pattern of creating the future or some other resource in the closure is good to know, as it can be necessary to avoid lifetime issues in some cases, but it shouldn't matter here.
For example, if you need to do something that requires mutable access, then you can't do it in the async block, as buffer_unordered will run multiple async blocks at the same time, and mutable access requires exclusive access. However, the closure does not happen concurrently, and as such can do things that require mutable access.
My guess is that the latter version is slightly easier on the optimizer.
Yes, it really is using the workers. It's just that only the code in the async block, and not the code in the closure, runs concurrently.
let mut bodies = stream::iter(vec!["test".to_string()])
.map(|url| {
// this part does not happen concurrently
let send_fut = client.get(&url).send();
async move {
// but this part does
(send_fut.await, url)
}
})
.buffer_unordered(workers);
Ok thank you !
I guess the question was a little stupid but I wanted to be sure I didn't make a mistake, rust is really fun but really hard for me too !
One interesting thing about async/await in Rust is that tasks are made asynchronous by repeatedly swapping the current task, but swapping can only happen at an .await. This is another way to see that the closure cannot be concurrent, as it cannot have an .await.