そのエラーメッセージはもしかして  async/await関連

# はじめに

デバッグはエラーメッセージとの戦いです。一つひとつのエラーメッセージへの対応方法を覚えていくと、開発のペースも上がっていきます。

ここでは、初心者的に行き詰った、async/await関連のエラーメッセージを振り返ります。

なお、非同期ランタイムには tokio または actix-rt を使用しているものとします。

---

# method not found in \`impl Future\` (Futureの実装にメソッドが見つからない)

---

## 間違っているコード

async関数を一つ定義します。[reqwest](https://docs.rs/reqwest/0.11.1/reqwest/) クレートを使用して、指定したURLにHTTPリクエストを送信し、そのレスポンスを受け取ります。そのボディの内容をテキストとして出力するコード書きました。このコードはコンパイルに失敗します。

```rust:lib.rs
pub async fn get_html() -> Result<(), GetHtmlError> {
    let response = reqwest::get("https://www.rust-lang.org");
    let body = response.text().await?;
    println!("{:?}", &body);
    Ok(())
}
```

```
error[E0599]: no method named `text` found for opaque type `impl Future` in the current scope
  --> src/lib.rs:14:25
   |
14 |     let body = response.text().await?;
   |                         ^^^^ method not found in `impl Future`
```

Futureの実装に(textという)メソッドが見つからない、というメッセージです。コードに直接的にはFutureという単語は登場しておらず、なんのことかわかりません。また、このメッセージが指し示している行をどれだけ眺めても、構文間違いは見つかりません。詰みました。

---

## 実行できるコード

間違えているのは一つ前の行で`.await?`を忘れている、という部分です。

```rust:lib.rs
pub async fn get_html() -> Result<(), GetHtmlError> {
    // let response = reqwest::get("https://www.rust-lang.org");  <- 間違い
    let response = reqwest::get("https://www.rust-lang.org").await?; // <- 正しい
    let body = response.text().await?;
    println!("{:?}", &body);
    Ok(())
}
```

変数`response`の値はreqwest::Response型のオブジェクトになることを想定していますが、`.await?`がないため、コンパイラに`Future`型であると解釈された結果でした。

---

## このメッセージはもしかして

method not found in `impl Future`

↓

`.await?` を忘れている行があるよ！

...という意味かもしれません。

---

# async functions cannot be used for tests (async関数はテストでは使用できない)

---

## 間違っているコード

先ほどのコードを実行するテストを書きました。assertが意味をなしていませんが、まずはコンパイルできるかを確認するため、`cargo test`コマンドを実行してみます。そして、このコードはコンパイルに失敗します。

```rust:tests/get_html_test.rs
#[test]
async fn it_works() {
    get_html().await.unwrap();
    assert_eq!(true, true);
}
```

```
error: async functions cannot be used for tests
 --> tests/get_html_test.rs:4:1
  |
4 |   async fn it_works() {
  |   ^----
  |   |
  |  _`async` because of this
  | |
5 | |     get_html().await.unwrap();
6 | |     assert_eq!(true, true);
7 | | }
  | |_^
```

async関数はテストでは使用できないと言われました。意気揚々とテストコードを書き始めましたが、1行で詰みました。

---

## 実行できるコード

```rust:get_html_test.rs
// #[test] <- 間違い
#[tokio::test] // <- 正しい
async fn it_works() {
    get_html().await.unwrap();
    assert_eq!(true, true);
}
```

[The Rust Programming Language 日本語版](https://doc.rust-jp.rs/book-ja/)の「テストの記述法」に従って書きましたが、これだけでは情報が足りませんでした。

[tokio](https://docs.rs/tokio/1.2.0/tokio/) のドキュメント内、「Attribute Macros」に説明がありました。

---

**test**

rt and macros Marks async function to be executed by runtime, suitable to test environment

test属性は、テスト環境において、ランタイムによりasync関数が実行されることを記述するためのものである

[test](https://docs.rs/tokio/1.2.0/tokio/attr.test.html) の説明ページに、属性の記述方法が書かれています。すなわち、`#[tokio::test]`と記述する、ということでした。

---

## このメッセージはもしかして

async functions cannot be used for tests

↓

使用している非同期ランタイムのドキュメントを読もう！

...ということかもしれません。

---

# functions in traits cannot be declared \`async\` (トレイト内で関数はasyncとして定義することはできない)

---

## 間違っているコード

トレイトにasync関数の定義を試みます。このコードはコンパイルに失敗します。

```rust:lib.rs
pub struct WebPage {}

pub trait GetHtml {
    // トレイトにasync fnを定義したい
    async fn get_html(&self) -> Result<(), GetHtmlError>;
}

impl GetHtml for WebPage {
    async fn get_html(&self) -> Result<(), GetHtmlError> {
        let response = reqwest::get("https://www.rust-lang.org").await?;
        let body = response.text().await?;
        println!("{:?}", &body);
        Ok(())
    }
}
```

```
error[E0706]: functions in traits cannot be declared `async`
  --> src/lib.rs:19:5
   |
19 |     async fn get_html(&self) -> Result<(), GetHtmlError>;
   |     -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |     |
   |     `async` because of this
   |
   = note: `async` trait functions are not currently supported
   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
```

トレイト内で関数はasyncとして定義することはできない、というメッセージです。

注釈に外部クレートの利用を検討しろと書いてありますが、言語自体が持つ機能を利用するのに外部クレートの追加が必要なんてことはないだろうという勝手な認識で、少しコードを変更してみます。

---

async関数を構造体のメソッドとして定義します。そして、トレイトの関数からそのメソッドを呼び出すことにします。

```rust:lib.rs
impl WebPage {
    // async fnは構造体自体のメソッドとして定義する
    async fn async_get_html(&self) -> Result<(), GetHtmlError> {
        let response = reqwest::get("https://www.rust-lang.org").await?;
        let body = response.text().await?;
        println!("{:?}", &body);
        Ok(())
    }
}

pub trait GetHtml {
    // トレイトで定義するのは通常の関数とする
    fn get_html(&self) -> Result<(), GetHtmlError>;
}

impl GetHtml for WebPage {
    // 通常の関数からasync fnの呼び出しを試みる
    fn get_html(&self) -> Result<(), GetHtmlError> {
        let _ = self.async_get_html().await?;
        Ok(())
    }
}
```

```
error[E0728]: `await` is only allowed inside `async` functions and blocks
  --> src/lib.rs:49:17
   |
48 | /     fn get_html(&self) -> Result<(), GetHtmlError> {
49 | |         let _ = self.async_get_html().await?;
   | |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
50 | |         Ok(())
51 | |     }
   | |_____- this is not `async`
```

わかっていたことですが、通常の関数内で `.await`は使用できません。詰みました。

---

## 実行できるコード

```rust:Cargo.toml
use async_trait::async_trait;

#[async_trait] // <- トレイトの定義に属性を記述する
pub trait GetHtml {
    async fn get_html(&self) -> Result<(), GetHtmlError>;
}

#[async_trait] // <- 実装に属性を記述する
impl GetHtml for WebPage {
    async fn get_html(&self) -> Result<(), GetHtmlError> {
        let response = reqwest::get("https://www.rust-lang.org").await?;
        let body = response.text().await?;
        println!("{:?}", &body);
        Ok(())
    }
}
```

注釈に従って、`async-trait`クレートを導入します。

ドキュメントの「[Explanation](https://docs.rs/async-trait/0.1.42/async_trait/#explanation)」に記述がある通り、このクレートは小難しいコードを簡単に書けるようにするもので、機能を追加するものではありませんでした。自分の思い込みの間違いでした。

---

## このメッセージはもしかして

functions in traits cannot be declared \`async\`

↓

ドキュメントを読んで正しく利用しよう！

...ということかもしれません。

---

# \`await\` is only allowed inside \`async\` functions and blocks (awaitはasync関数またはasyncブロック内でのみ許可されている)

---

## 間違っているコード

[Actix](https://actix.rs/book/actix/) を利用します。Actixは平行アプリケーション開発のフレームワークを提供するRustのライブラリです。フレームワークの定義に従い、アクターのハンドラーを作成します。その中で、async関数の呼び出しを試みます。このコードはコンパイルに失敗します。

```rust:lib.rs
// Actorのハンドラーを定義する
impl Handler<Msg> for GetHtmlActor {
    type Result = Result<bool, GetHtmlError>;

    // ハンドラーは通常の関数で定義する
    fn handle(&mut self, _msg: Msg, _ctx: &mut Context<Self>) -> Self::Result {
        let _ = get_html().await?;
        Ok(true)
    }
}
```

```
error[E0728]: `await` is only allowed inside `async` functions and blocks
  --> src/lib.rs:44:17
   |
43 | /     fn handle(&mut self, _msg: Msg, _ctx: &mut Context<Self>) -> Self::Result {
44 | |         let _ = get_html().await?;
   | |                 ^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
45 | |         Ok(true)
46 | |     }
   | |_____- this is not `async`
```

現在のバージョンのActixでは、アクターのハンドラーは通常の関数として定義します。そのため、関数内で直接`.await`は使用できません。初めてのActix開発、コーディング開始10分で詰みました。

---

## 実行できるコード(例)

解決する方法はいくつかあるようですが、自分がコンパイル、実行できたのは、[async-std](https://docs.rs/async-std/1.9.0/async_std/) クレートを利用する方法でした。

```toml:Cargo.toml
async-std = { version = "~1.9.0", features = [ "tokio1" ] }
```

```rust:lib.rs
impl Handler<Msg> for GetHtmlActor {
    type Result = Result<bool, GetHtmlError>;

    // ハンドラーは通常の関数で定義する
    fn handle(&mut self, _msg: Msg, _ctx: &mut Context<Self>) -> Self::Result {
        // asyncブロックを定義し、その中でawaitを使用する
        let get_html_task = task::spawn(async {
            get_html().await?;
            Ok(true)
        });
        task::block_on(get_html_task)
    }
}
```

asyncブロックを定義し、その中で`.await`を使用します。asyncブロック自体はasync-stdの仕組みで実行します。

---

## このメッセージはもしかして

\`await\` is only allowed inside \`async\` functions and blocks

↓

asyncブロックを実行できる仕組みを利用しよう！

...ということかもしれません。

---

# おわりに

どの開発言語、フレームワークでも、エラーメッセージからは直接修正方法を読み取れないことがあります。

もちろん同じメッセージでも状況によって対応方法は変わってきますが、知っているメッセージが増えてくれば、ドキュメントを読んだりネットを検索したりする時間を省略して、デバッグが効率的になります。

知っているメッセージを増やして、脱初心者を目指していきましょう。