< 返回版块

elimsc 发表于 2019-08-23 11:15

一段 actix-web 中的示例代码

fn main() {
    HttpServer::new(|| {
        App::new()
            .wrap_fn(|req, srv| { // 为什么这里不能用 wrap ?
                println!("Hi from start. You request: {}", req.path());
                srv.call(req).map(|res| {
                    println!("hi from response");
                    res
                })
            })
            .service(web::resource("/index").to(|| {
                println!("hello in handler");
                "hello middleware"
            }))
    })
    .bind("127.0.0.1:8080")
    .unwrap()
    .run()
    .unwrap();
}

问题一:为什么上面的 wrap_fn 不能换成 wrap, 因为我看到 warp_fn 中也是直接调用 wrap 函数的,为什么这里就不行了呢

// wrap_fn 的代码
pub fn wrap_fn<B1, F, R>(
    self,
    mw: F,
) -> App<
    impl NewService<
        Config = (),
        Request = ServiceRequest,
        Response = ServiceResponse<B1>,
        Error = Error,
        InitError = (),
    >,
    B1,
>
where
    B1: MessageBody,
    F: FnMut(ServiceRequest, &mut T::Service) -> R + Clone,
    R: IntoFuture<Item = ServiceResponse<B1>, Error = Error>,
{
    self.wrap(mw)
}

// wrap 的代码
pub fn wrap<M, B1, F>(
    self,
    mw: F,
) -> App<
    impl NewService<
        Config = (),
        Request = ServiceRequest,
        Response = ServiceResponse<B1>,
        Error = Error,
        InitError = (),
    >,
    B1,
>
where
    M: Transform<
        T::Service,
        Request = ServiceRequest,
        Response = ServiceResponse<B1>,
        Error = Error,
        InitError = (),
    >,
    B1: MessageBody,
    F: IntoTransform<M, T::Service>,
{
    let endpoint = apply_transform(mw, self.endpoint);
    App {
        endpoint,
        data: self.data,
        data_factories: self.data_factories,
        services: self.services,
        default: self.default,
        factory_ref: self.factory_ref,
        config: self.config,
        external: self.external,
        _t: PhantomData,
    }
}

问题二: 把上面闭包函数体中的内容提取出来,写成下面这样为什么是错的呢?

fn main() {
    // 闭包体提取出来
    let app = App::new()
        .wrap_fn(|req, srv| {
            println!("Hi from start. You request: {}", req.path());
            srv.call(req).map(|res| {
                println!("hi from response");
                res
            })
        })
        .service(web::resource("/index").to(|| {
            println!("hello in handler");
            "hello middleware"
        }));

    HttpServer::new(|| app)
        .bind("127.0.0.1:8080")
        .unwrap()
        .run()
        .unwrap();
}

这两个应该是一个类型的问题吧--

请各位大大能耐心解答下,给个相关的链接也可以,谢谢!!

评论区

写评论
lygz5016 2019-08-26 12:57

粗略回答, 第一个问题: wrap 和 wrap_fn 参数约束不一样。 where 表明了各自的参数约束,wrap 的F要实现特征IntoTransfrom,而wrap_fn的F要实现特征IntoFuture。

第二个问题: HttpServer要求F 有Send特性, 而App 是!Send特性。 把App放在闭包外这肯定不行。闭包是通过引用获取变量。

说白了,就是HttpServer是多线程的,App是不能被多线程共享的

1 共 1 条评论, 1 页