我试图实现一个塔层使用塔::layer_fn和塔::service_fn助手函数像这样(编译好):
use std::convert::Infallible;
use tower::Service;
use tower::util::ServiceFn;
tower::ServiceBuilder::new()
.layer_fn(|mut service: ServiceFn<_>| {
// Just do nothing except calling the downstream service
tower::service_fn(move |request| {
service.call(request)
})
})
.service_fn(|request: String| {
// Echo service
async move {
let response = request;
Ok::<_, Infallible>(response)
}
});
因为我在实际代码中有多个.await
点,我想避免手工实现Layer
,即Service::call()
,而是在async
块中这样做。对于echo服务,这确实工作得很好,如上所示。但是,对于layer_fn
中的服务,这不会编译:
tower::ServiceBuilder::new()
.layer_fn(|mut service: ServiceFn<_>| {
tower::service_fn(move |request| {
// Just do nothing except calling the downstream service
async move {
let response: Result<String, Infallible> = service.call(request).await;
// Do something with response, await'ing thereby
response
}
})
})
.service_fn(|request: String| {
// Echo service
async move {
let response = request;
Ok::<_, Infallible>(response)
}
});
});
我得到以下错误,但我不知道如何帮助编译器键入:
error[E0698]: type inside `async` block must be known in this context
--> src/main.rs:32:64
|
32 | let response: Result<String, Infallible> = service.call(request).await;
| ^^^^^^^ cannot infer type
|
note: the type is part of the `async` block because of this `await`
--> src/main.rs:32:85
|
32 | let response: Result<String, Infallible> = service.call(request).await;
| ^^^^^^
异步上下文中的类型推断有时不如同步上下文中强大。不幸的是,我能看到的唯一解决方案是使用夜间type_alias_impl_trait
:
#![feature(type_alias_impl_trait)]
type Fut = impl Future<Output = Result<String, Infallible>>;
type Callback = impl Fn(String) -> Fut;
tower::ServiceBuilder::new()
.layer_fn(|mut service: ServiceFn<Callback>| {
tower::service_fn(move |request| {
// Just do nothing except calling the downstream service
async move {
let response: Result<String, Infallible> = service.call(request).await;
// Do something with response, await'ing thereby
response
}
})
})
.service_fn::<Callback>(|request: String| {
// Echo service
async move {
let response = request;
Ok::<_, Infallible>(response)
}
});
或者将回调和future都装箱:
type Fut = Pin<Box<dyn Future<Output = Result<String, Infallible>>>>;
type Callback = Box<dyn Fn(String) -> Fut>;
tower::ServiceBuilder::new()
.layer_fn(|mut service: ServiceFn<Callback>| {
tower::service_fn(move |request| {
// Just do nothing except calling the downstream service
async move {
let response: Result<String, Infallible> = service.call(request).await;
// Do something with response, await'ing thereby
response
}
})
})
.service_fn::<Callback>(Box::new(|request: String| {
// Echo service
Box::pin(async move {
let response = request;
Ok::<_, Infallible>(response)
})
}));