gpt4 book ai didi

rust - 当根据特征定义提取函数的返回类型时,如何提取 Rust 中的一部分函数?

转载 作者:行者123 更新时间:2023-12-01 23:14:34 25 4
gpt4 key购买 nike

问题

我将 Rust 与 vscode 以及“Rust and Friends”带来的插件一起使用v1.0.0”。

我想使用提取函数技术重构一个长函数,但在某些情况下,IDE 无法确定提取函数的返回类型。

我认为原因是类型是根据特征描述的,不可能将该类型定义为返回类型。

由于我是 Rust 的新手,我希望我的评估不准确,所以我将提供一个示例。

例子

我正在使用回形针箱来设置 REST 服务器。配置服务器的部分如下所示:

let server = HttpServer::new(move || {
let app = App::new()
.wrap(Logger::default())
.wrap_api()
.data(pool.clone());

let app = app.service(
web::scope(“/api”).service(
web::scope(“/customers”).service(
web::resource(“/transactions”)
.route(web::get().to(schema_handlers::get_transactions))
.route(web::post().to(schema_handlers::add_transaction)),
),
),
);

let app = app.service(
web::scope(“/api”).service(
web::scope(“/admin”).service(
web::resource(“/permissions”)
.route(web::get().to(schema_handlers::get_permissions))
.route(web::post().to(schema_handlers::add_permission)),
),
),
);

app.with_json_spec_at("/api/spec").build()
})
.bind(format!("0.0.0.0:{}", port))?
.run();

paperclip 支持流畅的 API,因此可以链接所有服务定义,但我更愿意为我添加的每个处理程序范围提取一个函数。

这就是为什么我最初将单个流畅的调用分成两个单独的作业的原因。

下一步是提取每个 let app = app.service (语句转换为函数。

但要这样做,我需要能够表达 app 的类型或者至少是暴露 service 的特征的名称此处使用的方法。

在这种情况下,IDE 无法检测类型。

当我使用 The “let” type trick in Rust以及 IDE 中的一些提示,我得出的结论是类型是:

App<impl ServiceFactory<Config = (), Request = ServiceRequest, Response = ServiceResponse<StreamLog<Body>>, Error = Error, InitError = ()>, StreamLog<Body>>

此类型不能明确用于限定 app变量也不能用作提取函数的返回类型,该函数将替换对 app 赋值的右侧.

根据编译器错误消息,我了解到类型表达式中存在特征(如 impl 关键字的存在所示)是导致此问题的原因。

另一个问题是这种类型规范非常冗长。

我可以通过类型别名来解决冗长问题,但编译会提示 impl类型别名不稳定,在我看来这归结为同一个问题。

从例子中学习

在我看来,有些情况下类型定义明确并且可以由编译器推断,但是因为它们包含特征定义,所以不能(轻松)显式编写它们,因此 extract function重构方法并不总是可行的。

在我看来,这似乎是该语言的一个重要限制。

现在有没有一种方法可以提取函数(无需等待 Rust 中的特征别名)?

最佳答案

我假设您希望通过重构来改变这一点:

let app = app.service(
web::scope("/api").service(
web::scope("/customers").service(
web::resource("/transactions")
.route(web::get().to(schema_handlers::get_transactions))
.route(web::post().to(schema_handlers::add_transaction)),
),
),
);

像这样:

fn add_transaction_routes(app: App) -> App {
app.service(
web::scope("/api").service(
web::scope("/customers").service(
web::resource("/transactions")
.route(web::get().to(schema_handlers::get_transactions))
.route(web::post().to(schema_handlers::add_transaction)),
),
),
)
}

let app = add_transaction_routes(app);

当然这是行不通的,因为 App 是通用的并且不完整。您可以使用 impl Trait 作为参数和返回类型,如下所示:

fn add_transaction_routes(
app: App<impl ServiceFactory<...>, Body>,
) -> App<impl ServiceFactory<...>, Body> {

但我认为这是轻微的误用。虽然本身可能不是不正确的,impl Trait是单独推导出来的。函数签名表示传入的 app 可能与返回的类型不同,但 .service() 实际上返回 Self .所以把它变成一个简单的通用函数会更合适:

fn add_transaction_routes<T>(app: App<T, Body>) -> App<T, Body>
where
T: ServiceFactory<...>,
{

然后您可以选择创建一个 super 特征来减少调用 .service() 所需的样板代码:

ServiceFactory<
ServiceRequest,
Config = (),
Response = ServiceResponse<Body>,
Error = Error,
InitError = (),
>

但这一切开始变得困惑。虽然这是可能的,但很明显,这种类型的组织并不是专门为之设计的。相反,我建议您的重构围绕提供服务而不是围绕将它们添加到 App 进行。我认为这更清楚:

fn transaction_routes() -> impl HttpServiceFactory {
web::scope("/api").service(
web::scope("/customers").service(
web::resource("/transactions")
.route(web::get().to(schema_handlers::get_transactions))
.route(web::post().to(schema_handlers::add_transaction)),
),
)
}

let app = app.service(transaction_routes());

关于rust - 当根据特征定义提取函数的返回类型时,如何提取 Rust 中的一部分函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69247159/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com