Comments (8)
You may move some things and reference some things by creating a variable that's a reference and then moving that. For example:
async fn sum(idx: usize, num: u8) {
let sum = idx + num as usize;
println!("Sum = {}", sum);
}
async fn test() {
let other_value = 1;
let other_value_ref = &other_value;
let results = futures::future::join_all(
(0..10).into_iter()
.enumerate()
.map(|(idx, num)| {
async move {
sum(idx, num + other_value_ref).await;
}
})
).await;
dbg!(results);
}
from rust.
@theemathas thanks for the reply. (No offense) I honestly think that reference in your code is a bit awkward, because we need to do extra work that is conceptually a no-op.
I actually just tested my example with nightly rustc. It gave a more self-consistent error by saying that both idx
and num
need to be moved.
error[E0373]: async block may outlive the current function, but it borrows `num`, which is owned by the current function
--> src/main.rs:12:17
|
12 | / async {
13 | | sum(idx, num).await;
| | --- `num` is borrowed here
14 | | }
| |_________________^ may outlive borrowed value `num`
|
note: async block is returned here
--> src/main.rs:12:17
|
12 | / async {
13 | | sum(idx, num).await;
14 | | }
| |_________________^
help: to force the async block to take ownership of `num` (and any other referenced variables), use the `move` keyword
|
12 | async move {
| ++++
error[E0373]: async block may outlive the current function, but it borrows `idx`, which is owned by the current function
--> src/main.rs:12:17
|
12 | / async {
13 | | sum(idx, num).await;
| | --- `idx` is borrowed here
14 | | }
| |_________________^ may outlive borrowed value `idx`
|
note: async block is returned here
--> src/main.rs:12:17
|
12 | / async {
13 | | sum(idx, num).await;
14 | | }
| |_________________^
help: to force the async block to take ownership of `idx` (and any other referenced variables), use the `move` keyword
|
12 | async move {
| ++++
For more information about this error, try `rustc --explain E0373`.
My rustc is
rustc --version --verbose
rustc 1.81.0-nightly (4bc39f028 2024-06-26)
binary: rustc
commit-hash: 4bc39f028d14c24b04dd17dc425432c6ec354536
commit-date: 2024-06-26
host: aarch64-apple-darwin
release: 1.81.0-nightly
LLVM version: 18.1.7
I also tried your code with this nightly rustc. It turns out the same compile error.
from rust.
Compiles if changed to
.map(|(idx, num)| sum(idx, num))
or.map(async |(idx, num)| sum(idx, num).await)
under experimental featureasync_closure
|…| async { … }
≠ async |…| …
(https://hackmd.io/@compiler-errors/async-closures).
from rust.
@fmease thanks!
.map(|(idx, num)| sum(idx, num))
This works for this example which I intentionally reduced a lot. My actual code is a bit complicated. And I think it does not generalize to all use cases of closures.
.map(async |(idx, num)| sum(idx, num).await) under experimental feature async_closure
|…| async { … } ≠ async |…| … (https://hackmd.io/@compiler-errors/async-closures).
Yes, the blog post covers a more generalized and complicated scenarios in which the data may not be a plain old number. But I still don't know why rustc can't just copy that plain old data for me. I think my intent expressed in the code should be clear to the compiler and I think it's totally safe and sound to do that.
from rust.
@ifsheldon Right, makes sense. I can't answer your more general question right now about capturing copyables by move by default (I'm short on time). Have you tried |…| async move { … }
in your actual project? That fixes the code you posted at least and it's stable.
from rust.
Have you tried |…| async move { … }
OK, I should not have reduced my code too much as I thought other details were not relevant. A more complete yet reduced code look like this.
use std::time::Duration;
use tokio::time::sleep;
async fn sum(idx: usize, num: u8) -> usize {
// the code logic is a mock for actual computation and
// extracted from the closure to inform rustc
// that I need idx and num as values so that it should just copy them for me
idx + num as usize
}
async fn logging_mock(result: usize, id: usize) {
println!("Result={}, id = {}", result, id);
}
async fn mock_request(result: usize, request_string: String, request_configs: &str) -> Result<(), String> {
// request fn consumes `request_string` and `result` and references `request_configs` that is super large and I would rather not clone
dbg!("Requesting {} with {} and {}", result, request_string, request_configs);
Ok(())
}
#[derive(Debug)]
struct Configs {
request_template: String,
super_large_config: String,
some_other_data: String,
}
#[tokio::main]
async fn main() {
let mut configs = Configs {
request_template: "hello".to_string(),
super_large_config: "world".to_string(),
some_other_data: String::new(),
};
let results = futures::future::join_all(
(0..10).into_iter()
.enumerate()
.map(|(idx, num)| {
async {
let s = sum(idx, num).await;
// comment out the above line and simple mocks below make the code compiled
// let s = 1;
// let idx = 1;
let template = configs.request_template.clone();
mock_request(s, template, &configs.super_large_config).await.unwrap();
// non-emergent logging, prevents accidental DoS attack
sleep(Duration::from_millis(idx as u64)).await;
logging_mock(s, idx).await;
}
})
).await;
configs.some_other_data.push_str("do something to configs");
dbg!(configs);
dbg!(results);
}
Yes I can workaround this with more code refactoring (and I did), but I think focusing solving this case in this code is a bit too restricted and shortsighted. This issue is not about how to workaround a problem but why this problem (rustc can't copy a Copyable for me when using async closures) happens.
from rust.
You should probably use async move {}
like @fmease suggested, but you need to take a reference of &config
manually to move it into the async block:
ctrl+f the line // !!!
from rust.
Also ironically the code ICEs with async closures (async || { ... }
). I'll fix that 🫡
from rust.
Related Issues (20)
- Regression in `#[used]` attribute on Windows msvc HOT 16
- ICE in TaggedSerializer (serde) HOT 2
- missed optimization: coalese PathBuf reallocation HOT 5
- `thread 'rustc' panicked at compiler/rustc_codegen_ssa/src/back/link.rs:2700:27: index out of bounds: the len is 41 but the index is 41` HOT 1
- Vxworks build error for current master branch. Need to update some source. HOT 8
- rustdoc: add link prefix which would allow overwriting explicit links with item links
- Left-padding using format! does not work when using a fmt::Display as the argument HOT 4
- ICE: Cannot Eq compare incompatible types *mut T/#0 and *const T/#0 HOT 2
- Rust binaries cannot load relocatable libraries on macOS without `-rpath`
- Rust suggests invalid syntax for returning a method call in E0282
- Should tokens passed through `macro_rules` be able to join? HOT 1
- rustc ignores first exposed private type / span incorrect
- spurious ci failure: `The process cannot access the file because it is being used by another process` HOT 1
- A problem has to do with tuple and println!()
- Unresolved symbol linker error when running `cargo test` with an `#[used]` static variable on Windows HOT 2
- Assertion failure: Unexpected captures in ABI-compatible shim for Fn/FnMut implementation of coroutine-closure HOT 1
- ICE: assertion failed `Alias(Projection, ..` != `FreshTy(0)` HOT 3
- ICE: `associated_type_for_effects: Defid .. should be Trait or Impl but is TraitAlias` HOT 1
- ICE: `expected type for .. but found Const(false) when instantiating` HOT 1
- ICE: `parent item: DefId(0:5 ~ a[9a36]::{impl#1}) not marked as default` HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rust.