How to specific the return type of an async block

I want to make a asynchronous loop, which has no break in it and contains an asynchronous function that will returns a Result, here I used wait_a_second_and_return_ok to replace it. Logically this code can only returns Err(()) and actually it will keep looping until I kill the process.
Here is the code:

#[tokio::main]
async fn main(){

    async fn wait_a_second_and_return_ok()->Result<(),()>{
        tokio::time::sleep(std::time::Duration::from_secs(1)).await;
        Ok(())
    }

    let a=async {
        loop{
            wait_a_second_and_return_ok().await?;
        }
    };

    //...and more operations

}

But the compiler didn't permit me to do so:

error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `Try`)
  --> src/main.rs:17:13
   |
15 |       let a=async {
   |  _________________-
16 | |         loop{
17 | |             wait_a_second_and_return_ok().await?;
   | |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in an async block that returns `()`
18 | |         }
19 | |     };
   | |_____- this function should return `Result` or `Option` to accept `?`
   |
   = help: the trait `Try` is not implemented for `()`
   = note: required by `from_error`

Alright, I added a return type:

#[tokio::main]
async fn main(){

    async fn wait_a_second_and_return_ok()->Result<(),()>{
        tokio::time::sleep(std::time::Duration::from_secs(1)).await;
        Ok(())
    }

    let a=async {
        loop{
            wait_a_second_and_return_ok().await?;
        }
        Result::<(),()>::Ok(())
    };

}

The compiler didn't throw error this time, but as expectation it printed a warning.

warning: unreachable expression
  --> src/main.rs:19:9
   |
16 | /         loop{
17 | |             wait_a_second_and_return_ok().await?;
18 | |         }
   | |_________- any code following this expression is unreachable
19 |           Result::<(),()>::Ok(())
   |           ^^^^^^^^^^^^^^^^^^^^^^^ unreachable expression
   |
   = note: `#[warn(unreachable_code)]` on by default

Although a warning isn't harmful, but I still wonder is there a way to eliminate it, or a more elegant way to specific the return type?

There is no syntax for specifying the return type directly. The easiest way to get this to work is to simply use the async block in a way that requires it to have a specific return type, as the compiler will then infer the return type from that use.

One thing you could do is this:

use std::future::Future;

fn set_return_type<T, F: Future<Output = T>>(_arg: &F) {}

#[tokio::main]
async fn main() {

    async fn wait_a_second_and_return_ok()->Result<(),()>{
        tokio::time::sleep(std::time::Duration::from_secs(1)).await;
        Ok(())
    }

    let a = async {
        loop {
            wait_a_second_and_return_ok().await?;
        }
    };
    
    set_return_type::<Result<(), ()>, _>(&a);
}
4 Likes

I got it, but it still too complex. Why async block doesn't automatically infer the return type from '?' expression?

Because the question mark operator inserts an error conversion, and the output of the conversion is ambiguous.

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.