What if some branches in pattern matching need to use asynchrony and some don't

Rust Playgroundrust playground

How to make him compile and pass

async fn add(n:i32) -> i32{
    n+1
}

async fn test() -> i32{
    Ok(1).map(|n| async { add(n).await })
    .unwrap_or_else(|_| async { 0 }).await
}

fn main() {
    let n = block_on(test());
    println!("{}", n);
}
  |
8 |     Ok(1).map(|n| async { add(n).await })
  |                         ---------------- the expected `async` block
9 |     .unwrap_or_else(|_| async { 0 }).await
  |                               ^^^^^ expected `async` block, found a different `async` block
  |
  = note: expected `async` block `[static generator@src/main.rs:8:25: 8:41]`
             found `async` block `[static generator@src/main.rs:9:31: 9:36]`
async fn test() -> i32{
    match Ok(1) {
        Ok(n) => add(n).await,
        Err(_) => 0,
    }
}
2 Likes

must us match?

There's nothing must with enough code, but match would be the simplest for this specific case.

1 Like

Yes, But I want to know how to use closures to make this compilation pass。thanks :grinning_face_with_smiling_eyes:

You probably can't do that with multiple async blocks, since every async block generates its own, unique, and distinct impl Future type, just like every closure generates its own impl Fn(…) -> … type.

What you can do is introduce concrete and identical types for the generators, e.g. by relying on dyn Future. Here's a playground. But I think that's outright disgusting, especially in the light of the simple solution provided by @Hyeonu.

thanks,I just want to know why this doesn't work.Now I know.

By design, each async block has a unique type, which is incompatible with all other types of async blocks. An async block is not a piece of code to be executed, but a struct with a state machine inside, so async { 0 } is not returning a 0, it returns a unique Future-like object.

OTOH Code like unwrap_or requires the type in the option and the alternative to be exactly the same type.

You could unify types of async blocks via type erasure (BoxFuture), but that adds runtime overhead and unnecessary layer of abstraction to jam them into a helper function that wasn't designed to handle async at all.

Here's an in-depth explanation:

https://without.boats/blog/the-problem-of-effects/

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.