LoginSignup
5
3

More than 3 years have passed since last update.

anyhowを試していたら?と型でハマった

Last updated at Posted at 2020-11-10

初心者が、anyhowを試していた時にハマりました。

エラーの型でハマる

anyhow
https://docs.rs/anyhow/1.0.34/anyhow/

anyhowのサンプル

use std::fs::File;
use anyhow::Result;

fn main() -> Result<()> {
   let l = File::open("bar.txt")?;
   Ok(())
}

ファイルがないのでエラーが返ります。

Error: 指定されたファイルが見つかりません。 (os error 2)
error: process didn't exit successfully: `target\debug\test.exe` (exit code: 1)

anyhowはエラーをいい感じにまとめてくれるすばらしいやつです。
勝手にResultをすべてよしなにしてくれるような気になりました。

ふとそのまま返してみると

fn main() -> Result<()> {
   let l = File::open("bar.txt");

   match l {
       Ok(f) => f,
       Err(e) => return Err(e),
   };

   Ok(())
}

型が違うのでコンパイルエラーになってしまいました。

error[E0308]: mismatched types
  --> src\main.rs:10:29
   |
10 |        Err(e) => return Err(e),
   |                             ^ expected struct `anyhow::Error`, found struct `std::io::Error`

修正版

fn main() -> Result<()> {
   let l = File::open("bar.txt");

   match l {
       Ok(f) => f,
       Err(e) => return Err(e.into()),/*intoが必要*/
   };

   Ok(())
}

intoが必要でした。
?がキャストしてくれるのですぐに気づきませんでした。

余談ですが、anyhow::Errorが返るマクロもあるようです。

fn main() -> Result<()> {
   let l = File::open("bar.txt");

   match l {
       Ok(f) => f,
       Err(e) => return Err(anyhow!("エラー:{}",e)),
   };

   Ok(())
}
Error: エラー:指定されたファイルが見つかりません。 (os error 2)
error: process didn't exit successfully: `target\debug\test.exe` (exit code: 1)

非同期でハマる

普通にawaitする場合はそのまま

use anyhow::*;
use tokio::fs::File;

#[tokio::main]
async fn main() -> Result<()> {
    File::open("foo.txt").await?;
    Ok(())

}
Error: 指定されたファイルが見つかりません。 (os error 2)
error: process didn't exit successfully: `target\debug\test.exe` (exit code: 1)

エラーが返ります。

よくspawnしている例があるのでspawnしてみると

#[tokio::main]
async fn main() -> Result<()> {
     let handle = tokio::spawn(File::open("foo.txt"));
     let result = handle.await?;

    Ok(())
}

エラーになるのを期待していたのですが、正常終了してしまいます。

修正版

#[tokio::main]
async fn main() -> Result<()> {
     let handle = tokio::spawn(File::open("foo.txt"));
     let result = handle.await??;  /*2ついる*/

    Ok(())
}

?が2つ必要でした。
handleはJoinHandleに包まれた型tokio::task::JoinHandle<std::result::Result<tokio::fs::File, std::io::Error>>
になっていてawaitすると
std::result::Result<std::result::Result<tokio::fs::File, std::io::Error>, tokio::task::JoinError>
とResultがネストした形になっているためでした。

結論

型をちゃんとみろってことですね。

追記

https://cha-shu00.hatenablog.com/entry/2020/12/08/060000
詳しく解説してくださっています。

5
3
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
5
3