rustanyhow

Mixing anyhow::Result with std::io::Result


Can anyone help me understand why this code compiles fine:

use actix_web::{App, HttpServer};
use anyhow::Result;

mod error;

#[actix_rt::main]
async fn main() -> Result<()> {
    HttpServer::new(|| App::new())
        .bind("127.0.0.1:8080")?
        .run()
        .await?;

    Ok(())
}

while this doesn't compile:

use actix_web::{App, HttpServer};
use anyhow::Result;

mod error;

#[actix_rt::main]
async fn main() -> Result<()> {
    HttpServer::new(|| App::new())
        .bind("127.0.0.1:8080")?
        .run()
        .await
}

with the error:

error[E0308]: mismatched types
 --> src/main.rs:6:1
  |
6 | #[actix_rt::main]
  | ^^^^^^^^^^^^^^^^^ expected struct `anyhow::Error`, found struct `std::io::Error`
7 | async fn main() -> Result<()> {
  |                    ---------- expected `std::result::Result<(), anyhow::Error>` because of return type
  |
  = note: expected enum `std::result::Result<_, anyhow::Error>`
             found enum `std::result::Result<_, std::io::Error>`
  = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

What is fundamentally different between the two examples?


Solution

  • The problem is that the second example is returning Result<(), std::io::Error> which is returned by starting the server, whereas the first one is returning Result<(), anyhow::Error> in the form of Ok(()).

    The reason the first example works is that the ? operator (or the try! macro) performs a conversion from whatever error is returned to the error of the return type of the function.

    From the docs:

    In case of the Err variant, it retrieves the inner error. try! then performs conversion using From. This provides automatic conversion between specialized errors and more general ones.