“impl Trait”的不同用途导致 rust 菌中不同的不透明类型

zbdgwd5y  于 2023-11-19  发布在  其他
关注(0)|答案(2)|浏览(134)

我定义了两个函数来封装actix_web响应,像这样:

pub fn box_actix_rest_response<T>(data: T) -> impl Responder where T: Serialize + Default{
    let res = ApiResponse {
        result: data,
        ..Default::default()
    };
    HttpResponse::Ok().json(res)
}

pub fn box_error_actix_rest_response <T>(data: T, result_code: String, msg: String) -> impl Responder where T: Serialize + Default {
    let res = ApiResponse {
        result: data,
        statusCode: "200".to_string(),
        resultCode: result_code,
        msg
    };
    HttpResponse::Ok().json(res)
}

字符串
一个函数 Package 正常响应,另一个 Package 错误响应,但是当我在同一个外层函数中使用这两个函数时,就像这样:

pub fn create_file(add_req: &TexFileAddReq, login_user_info: &LoginUserInfo) -> impl Responder {
    let new_file = TexFileAdd::gen_tex_file(add_req, login_user_info);
    use crate::model::diesel::tex::tex_schema::tex_file as cv_work_table;
    use crate::model::diesel::tex::tex_schema::tex_file::dsl::*;
    let mut query = cv_work_table::table.into_boxed::<diesel::pg::Pg>();
    query = query.filter(
        cv_work_table::parent
            .eq(add_req.parent.clone())
            .and(cv_work_table::name.eq(add_req.name.clone()))
            .and(cv_work_table::file_type.eq(add_req.file_type.clone())),
    );
    let cvs = query.load::<TexFile>(&mut get_connection()).unwrap();
    if !cvs.is_empty() {
        return box_error_actix_rest_response("already exists", "ALREADY_EXISTS".to_owned(), "file/folder already exists".to_owned());
    }
    let result = diesel::insert_into(tex_file)
        .values(&new_file)
        .get_result::<TexFile>(&mut get_connection())
        .expect("failed to add new tex file or folder");
    let resp = box_actix_rest_response(result);
    return resp;
}


显示错误:

mismatched types
expected opaque type `impl Responder` (opaque type at </Users/xiaoqiangjiang/.cargo/git/checkouts/rust_wheel-8476ff1b418e67f8/252bdd6/src/common/wrapper/actix_http_resp.rs:23:88>)
   found opaque type `impl Responder` (opaque type at </Users/xiaoqiangjiang/.cargo/git/checkouts/rust_wheel-8476ff1b418e67f8/252bdd6/src/common/wrapper/actix_http_resp.rs:15:47>)
distinct uses of `impl Trait` result in different opaque typesrustcClick for full compiler diagnostic
actix_http_resp.rs(23, 88): the expected opaque type
actix_http_resp.rs(15, 47): the found opaque type
file_service.rs(106, 81): expected `impl Responder` because of return type


看起来这两个函数返回不同的Responder,我应该怎么做来解决这个问题?可以像这样使用这两个函数吗?

px9o7tmv

px9o7tmv1#

当你为一个给定的trait返回一个类型impl Trait时,实际的底层类型被认为是不透明的,也就是说,它存在,编译器知道它是什么,但它必须被认为不同于当前作用域中的任何其他类型。这与你引入泛型类型时类似:即使(在单体化时)编译器知道实际类型,它的行为就像除了特征约束之外没有关于它的信息一样。
这样做的原因是每个函数的签名必须“独立”进行类型检查(同时考虑其他函数的签名)。如果您将box_actix_rest_response的实际返回类型更改为实现Response的其他类型,则不会更改其签名,但create_file无法进行类型检查。
两个来自不同来源的不透明类型 * 不能 * 统一,因此出现错误。这里你想要的是写实际的底层类型,而不是强迫类型变得不透明:在你的例子中,它是HttpResponse

pub fn box_actix_rest_response<T>(data: T) -> HttpResponse where T: Serialize + Default{
    let res = ApiResponse {
        result: data,
        ..Default::default()
    };
    HttpResponse::Ok().json(res)
}

pub fn box_error_actix_rest_response <T>(data: T, result_code: String, msg: String) -> HttpResponse where T: Serialize + Default {
    let res = ApiResponse {
        result: data,
        statusCode: "200".to_string(),
        resultCode: result_code,
        msg
    };
    HttpResponse::Ok().json(res)
}

字符串

yvfmudvl

yvfmudvl2#

再考虑一下auto_enums库,它允许你从同一个函数返回像这样的不透明类型。

相关问题