作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图写一个由两个异步函数组成的高阶函数。
我基本上是在寻找异步版本this
fn compose<A, B, C, G, F>(f: F, g: G) -> impl Fn(A) -> C
where
F: Fn(A) -> B,
G: Fn(B) -> C,
{
move |x| g(f(x))
}
到目前为止,这是我的尝试。
fn compose_future<A, B, C, G, F>(f: F, g: G) -> (impl Fn(A) -> impl Future<C>)
where
F: Fn(A) -> impl Future<B>,
G: Fn(B) -> impl Future<C>,
{
move |x| async { g(f(x).await).await }
}
我得到以下错误
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src\channel.rs:13:17
|
13 | F: Fn(A) -> impl Future<B>,
| ^^^^^^^^^^^^^^
有可能做到这一点吗?
最佳答案
我不确定是否可以使用impl Trait
-s做到这一点。我可以提出的一个解决方案是不使用async-await功能的老式的将来类型用法。 TLDR:full playground。 Async-await使用内部生成状态机的生成器,因此我们需要手动定义它:
enum State<In, F, FutOutF, G, FutOutG> {
Initial(In, F, G), // Out composed type created
FirstAwait(FutOutF, G), // Composed type waits for the first future
SecondAwait(FutOutG), // and for the second
// here can be a `Completed` state, but it simpler
// to handle it with `Option<..>` in our future itself
}
然后定义一个组合类型本身:
struct Compose<In, Out, F, FutOutF, G, FutOutG> {
state: Option<State<In, F, FutOutF, G, FutOutG>>,
_t: PhantomData<Out>,
}
// And "entry-point" would be something like that:
fn compose_fut<In, Out, F, FutOutF, G, FutOutG>(
i: In,
f: F,
g: G,
) -> Compose<In, Out, F, FutOutF, G, FutOutG> {
Compose {
state: Some(State::Initial(i, f, g)),
_t: PhantomData,
}
}
然后是最复杂的部分-
impl Future
本身,这里是没有实现的基本impl声明:
impl<In, Mid, Out, F, FutOutF, G, FutOutG> Future for Compose<In, Out, F, FutOutF, G, FutOutG>
where
FutOutF: Future<Output = Mid>,
F: FnOnce(In) -> FutOutF,
FutOutG: Future<Output = Out>,
G: FnOnce(Mid) -> FutOutG,
{
type Output = Out;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
// here comes the magic
}
}
转换的值如下:
In -> Mid -> Out
,其中
F
和
G
是我们的组合函数,它们的输出分别是
FutOutF
和
FutOutG
。最后是
Future::poll
实现:
let this = unsafe { self.get_unchecked_mut() };
let state = this.state.take();
match state {
None => Poll::Pending, // invalid state
Some(State::Initial(i, f, g)) => {
let fut = f(i);
this.state = Some(State::FirstAwait(fut, g));
cx.waker().wake_by_ref();
Poll::Pending
}
Some(State::FirstAwait(mut fut, g)) => {
let val = match unsafe { Pin::new_unchecked(&mut fut) }.poll(cx) {
Poll::Ready(v) => v,
Poll::Pending => {
this.state = Some(State::FirstAwait(fut, g));
return Poll::Pending;
}
};
let fut = g(val);
this.state = Some(State::SecondAwait(fut));
cx.waker().wake_by_ref();
Poll::Pending
}
Some(State::SecondAwait(mut fut)) => {
match unsafe { Pin::new_unchecked(&mut fut) }.poll(cx) {
Poll::Ready(v) => Poll::Ready(v),
Poll::Pending => {
this.state = Some(State::SecondAwait(fut));
Poll::Pending
}
}
}
}
我避免使用任何库来使其“普通”,通常,不安全的零件使用
pin-project
或
futures::pin_mut
处理。状态管理相当复杂,因此我建议重新检查实现情况,可能会出现错误。
关于asynchronous - 如何在Rust中编写两个异步函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62724721/
我是一名优秀的程序员,十分优秀!