Rust 如何实现一个“动态列表”;“中间件”;功能?
我正在编写一些代码,其结构类似于web框架中的“中间件”,因此我将在这个简单的示例中使用该术语。中间件功能的思想是它包装了实际的响应处理程序,因此它可以在请求到达处理程序之前修改请求,并在响应返回后修改响应:Rust 如何实现一个“动态列表”;“中间件”;功能?,rust,Rust,我正在编写一些代码,其结构类似于web框架中的“中间件”,因此我将在这个简单的示例中使用该术语。中间件功能的思想是它包装了实际的响应处理程序,因此它可以在请求到达处理程序之前修改请求,并在响应返回后修改响应: struct请求; 结构反应; 特质处理者{ fn handle(&self,request:request)->Response; } 特征中间件{ fn handle(&self,request:request,next:Box Response>)->Response; } 我考虑
struct请求;
结构反应;
特质处理者{
fn handle(&self,request:request)->Response;
}
特征中间件{
fn handle(&self,request:request,next:Box Response>)->Response;
}
我考虑过使用两个单独的函数,一个用于预处理请求,另一个用于后处理响应,但是如果不借助黑客,我将无法在请求期间存储任何附加状态
服务器包含动态配置的处理程序和中间件,因此它必须使用一些装箱的trait对象:
struct服务器{
处理者:盒子,
中间产品:Vec,
}
现在,如何实现响应处理?以下是我的两次尝试:
impl服务器{
//第一次尝试:使用迭代器::fold()
fn处理请求折叠响应{
让handler\u with\u middleware=self.middleware.iter()
.rev()
.fold:(&'a self,request:request,index:usize)->响应{
如果索引>=self.middleware.len(){
self.handler.handle(请求)
}否则{
让下一步=框::新建(
|r:Request | self.handle_Request_from(r,index+1));
self.middleware[index].handle(请求,下一个)
}
}
}
两次尝试都给出了相同的错误,这表明我在做一些根本错误的事情:
error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> src/lib.rs:25:67
|
19 | fn handle_request_fold<'a>(&'a self, request: Request) -> Response {
| -------- this data with lifetime `'a`...
...
25 | Box::new(|request| middleware.handle(request, next))
| ^^^^ ...is captured and required to live as long as `'static` here
error[E0759]:'self'具有生存期''a',但它需要满足''static'生存期要求
-->src/lib.rs:25:67
|
19 | fn处理|请求|折叠响应{
|-----此数据的生存期为“'a”。。。
...
25 | Box::new(| request | middleware.handle(request,next))
|^^^^…被捕获,并且需要在这里保持“静态”
我知道trait对象有一个隐式的'静态的
生存期,所以我尝试添加显式的生存期,正如你所看到的,但是没有帮助。我不明白为什么编译器会在这里的任何地方要求一个'静态的
生存期;没有任何东西(包括闭包)可以逃脱句柄请求*
函数,对吗
发布之后,我发现:传递给
中间件的装箱trait对象也需要一个非静态的生存期
trait Middleware {
fn handle<'a>(&self, request: Request,
next: Box<dyn FnOnce(Request) -> Response + 'a>)
-> Response;
}
有必要让中间件接受动态函数对象吗?我看不出全部情况,但对我来说,在构建中间件之后,您不太可能需要热交换这些函数。如果您需要另一个函数,您可以制作另一个中间件(因此你可以放弃泛型,而不需要在通过中间件的过程中生成数百万个盒子)@AlexLarionov它实际上不是我正在开发的一个web应用程序,而是一个数据处理管道在运行时从YAML文件加载。每个文件只调用一次,因此装箱的开销可以忽略不计。
fn handle_request_from(&self, request: Request, index: usize) -> Response {
if index >= self.middlewares.len() {
self.handler.handle(request)
} else {
let next = Box::new(
move |request| self.handle_request_from(request, index + 1));
self.middlewares[index].handle(request, next)
}
}