Rust中待提取函数返回类型关联trait时如何完成函数提取操作?
解决方案
你可以通过以下三种稳定可用的方案实现函数提取,不需要依赖尚未稳定的trait别名特性:
方案1:拆分路由作用域为独立函数(最常用)
你不需要把App实例传入提取的函数,直接将每个作用域的配置单独封装为返回HttpServiceFactory trait的函数即可,调用侧直接将返回值传入service方法:
// 提取customer相关路由 fn customers_routes() -> impl actix_web::dev::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)), ), ) } // 提取admin相关路由 fn admin_routes() -> impl actix_web::dev::HttpServiceFactory { 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)), ), ) }
重构后的主代码可以简化为:
let server = HttpServer::new(move || { App::new() .wrap(Logger::default()) .wrap_api() .data(pool.clone()) .service(customers_routes()) .service(admin_routes()) .with_json_spec_at("/api/spec") .build() }) .bind(format!("0.0.0.0:{}", port))? .run();
方案2:使用泛型约束封装App配置
如果你需要对App实例做批量公共配置,可以通过泛型约束实现,不需要写出完整的App泛型参数:
fn add_common_middlewares<T>(app: paperclip::actix::App<T>) -> paperclip::actix::App<T> where paperclip::actix::App<T>: paperclip::actix::Mountable { app.wrap(Logger::default()) .wrap_api() .data(global_config.clone()) }
方案3:全量App构建逻辑封装
你可以直接把整个App的构建逻辑封装为独立函数,返回位置用impl Trait标注即可,不需要暴露具体类型:
fn build_app(pool: DbPool) -> impl actix_web::dev::HttpServiceFactory { App::new() .wrap(Logger::default()) .wrap_api() .data(pool) .service(customers_routes()) .service(admin_routes()) .with_json_spec_at("/api/spec") .build() }
主代码只需要保留服务启动逻辑:
let server = HttpServer::new(move || build_app(pool.clone())) .bind(format!("0.0.0.0:{}", port))? .run();
原理解释
Rust稳定版早已支持**返回位置impl Trait(RPIT)**特性,该特性从Rust 1.26版本开始稳定,你只需要在函数返回值位置声明返回类型实现的对应trait,不需要写出完整的复杂类型,编译器会自动推断实际类型。你之前遇到的impl关键字报错,是因为你尝试将impl用在类型别名中,这属于尚未稳定的特性,但用在函数返回值位置是完全合法的。
内容的提问来源于stack exchange,提问作者David Sackstein
相关产品推荐
相关产品推荐

