LoginSignup
13
4

More than 3 years have passed since last update.

async ブロックの型を指定したい

Last updated at Posted at 2020-12-20

もうすこし忖度してほしい

asyncブロックはFuture<Output=何らかの戻り値型>になるのですが、Output型を直接指定する構文がありません。
なので例えば以下のようなコードを書くと:

main.rs
use std::error::Error;
use tokio::{self, signal};

async fn async_func() -> Result<(), Box<dyn Error>> {
    tokio::time::sleep(std::time::Duration::from_secs(3)).await;
    println!("Done");
    Ok(())
}
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn Error>> {
    let sig_term = async {
        let mut s = signal::unix::signal(signal::unix::SignalKind::terminate())?;
        s.recv().await;
        Ok(())
    };

    tokio::select! {
        result = sig_term => {
            result?;
            log::info!("SIGTERM");
        }
        val = async_func() => {
            val?
        }
    }
    Ok(())
}

sig_term変数の型の推測ができずコンパイルできません。

error[E0698]: type inside `async` block must be known in this context
  --> src/main.rs:14:9
   |
14 |         Ok(())
   |         ^^ cannot infer type for type parameter `E` declared on the enum `Result`
   |
note: the type is part of the `async` block because of this `await`
  --> src/main.rs:17:5
   |
17 | /     tokio::select! {
18 | |         result = sig_term => {
19 | |             result?;
20 | |             log::info!("SIGTERM");
...  |
24 | |         }
25 | |     }
   | |_____^
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

For more information about this error, try `rustc --explain E0698`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

プレイグラウンド: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=502eb9483c8d3d2c76bfd5ac99f4ee4f

すっきり解決

以下のスレッドにいろんな解決方法がありましたが、型変換を行うトレイトOutputtingを用意し、Futureに対して実装することで明示的に指定してみます。
https://internals.rust-lang.org/t/return-type-annotation-of-async-block/12561/14

main.rs
use std::error::Error;
use tokio::{self, signal};

// Outputting トレイト
trait Outputting: Sized {
    fn outputting<O>(self) -> Self
    where
        Self: std::future::Future<Output = O>,
    {
        self
    }
}

// Futureに実装
impl<T: std::future::Future> Outputting for T {}

async fn async_func() -> Result<(), Box<dyn Error>> {
    tokio::time::sleep(std::time::Duration::from_secs(3)).await;
    println!("Done");
    Ok(())
}

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn Error>> {
    let sig_term = async {
        let mut s = signal::unix::signal(signal::unix::SignalKind::terminate())?;
        s.recv().await;
        Ok(())
    }.outputting::<Result<(), Box<dyn Error>>>();  // asyncブロックに対してOutputの型を指定する

    tokio::select! {
        result = sig_term => {
            result?;
            log::info!("SIGTERM");
        }
        val = async_func() => {
            val?
        }
    }
    Ok(())
}

コンパイル出来ました。

プレイグラウンド: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7743dbdec2f52c9fdee49ccd7965f01d

13
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
4