Rust:预期类型,发现不透明类型

Dje*_*ent 8 types rust actix-web

我想在actix中制作一个用于渲染模板的辅助函数,如下所示:

fn render_response(
    tera: web::Data<Tera>,
    template_name: &str,
    context: &Context,
) -> impl Responder {
    match tera.render(template_name, context) {
        Ok(rendered) => HttpResponse::Ok().body(rendered),
        Err(_) => HttpResponse::InternalServerError().body("Failed to resolve the template."),
    }
}
Run Code Online (Sandbox Code Playgroud)

我在如下视图中使用它:

async fn signup(tera: web::Data<Tera>) -> impl Responder {
    let mut data = Context::new();
    data.insert("title", "Sign Up");

    render_response(tera, "signup.html", &data)
}
Run Code Online (Sandbox Code Playgroud)

如果视图与上面的一样简单,则一切正常,但如果视图稍微复杂一点,我就会遇到问题:

async fn login(tera: web::Data<Tera>, id: Identity) -> impl Responder {
    let mut data = Context::new();
    data.insert("title", "Login");

    if let Some(id) = id.identity() {
        return HttpResponse::Ok().body(format!("Already logged in: {}.", id));
    }

    render_response(tera, "login.html", &data)
}
Run Code Online (Sandbox Code Playgroud)

我得到的错误:

error[E0308]: mismatched types
   --> src\main.rs:101:5
    |
42  | ) -> impl Responder {
    |      -------------- the found opaque type
...
101 |     render_response(tera, "login.html", &data)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `actix_web::HttpResponse`, found opaque type
    |
    = note:     expected type `actix_web::HttpResponse`
            found opaque type `impl actix_web::Responder`
Run Code Online (Sandbox Code Playgroud)

我尝试将 提取return HttpResponse...到一个也返回 的单独函数中impl Responder,但现在出现了不同的错误:

error[E0308]: mismatched types
   --> src\main.rs:101:5
    |
42  | ) -> impl Responder {
    |      -------------- the found opaque type
...
101 |     render_response(tera, "login.html", &data)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
    |
    = note:     expected type `impl actix_web::Responder` (opaque type at <src\main.rs:104:28>)
            found opaque type `impl actix_web::Responder` (opaque type at <src\main.rs:42:6>)
    = note: distinct uses of `impl Trait` result in different opaque types
Run Code Online (Sandbox Code Playgroud)

我真的不明白为什么会发生以及如何解决它。

Pet*_*all 6

当函数返回类似 的内容时impl Responder,意味着它返回某种实现了Responder. 编译器可以推断出该类型,但它对任何调用者来说都是“不透明的”,这意味着您无法假设该类型实际上是什么。即使编译器有更多的信息,类型也总是在函数边界处匹配。这很重要,这样人们就可以在函数级别推理代码,而不必在头脑中保留有关程序各行的所有信息。

函数也必须只返回一种类型,因此当编译器遇到这样的函数时:

async fn login(tera: web::Data<Tera>, id: Identity) -> impl Responder {
    let mut data = Context::new();
    data.insert("title", "Login");

    if let Some(id) = id.identity() {
        return HttpResponse::Ok().body(format!("Already logged in: {}.", id));
    }

    render_response(tera, "login.html", &data)
}
Run Code Online (Sandbox Code Playgroud)

它看到最后的语句返回一个 opaque impl Responder,而早期的return语句返回一个crete HttpResponse。即使您知道它们实际上是同一类型,但这只是因为您碰巧知道如何render_response实现。这很好,因为它可以防止代码中不相关部分的更改破坏此函数:您不希望对主体的更改render_response导致.login

将 的返回类型更改render_response为具体类型,它将起作用:

fn render_response(
    tera: web::Data<Tera>,
    template_name: &str,
    context: &Context,
) -> HttpResponse;
Run Code Online (Sandbox Code Playgroud)

  • 明白了,我在想这就像其他语言的界面一样。任何实现给定特征的类型在这里都可以。我现在明白了。 (4认同)