在 Rust 中实现异步构建器模式

问题描述 投票:0回答:1

我想为建筑商实现一个未来。这对于例如通过构建器配置请求然后将其发送出去的示例来说很常见。

我想为构建器实现

IntoFuture
,但如果没有动态调度我就无法做到这一点。我的直觉告诉我,我应该能够做到这一点,而无需分配额外的内存。

例如

#[derive(Default)]
struct FooFluentBuilder {
    value: i32,
}

impl FooFluentBuilder {
    fn value(mut self, value: i32) -> Self {
        self.value = value;
        self
    }

    async fn send(self) -> Result<i32, &'static str> {
        Ok(self.value)
    }
}

impl std::future::IntoFuture for FooFluentBuilder {
    type Output = Result<i32, &'static str>;
    type IntoFuture = std::pin::Pin<Box<dyn std::future::Future<Output = Self::Output>>>;

    fn into_future(self) -> Self::IntoFuture {
        Box::pin(self.send())
    }
}

#[tokio::main]
async fn main() {
    let _response = FooFluentBuilder::default().value(5).send().await;
    let _response = FooFluentBuilder::default().value(5).await;
}

在此示例中,我将 Foo 请求转换为由

Pin<Box<dyn Future<Output = ...>>>
表示的动态未来。理想情况下,我想要
FooFluentBuilder::send
返回的类型,但
Future
类型是不透明的,无法通过 Rust 表示。

目前是否有现有机制可以在没有动态调度的情况下实现

IntoFuture

参见上面的示例。在那里我使用的是 dyn Future,但我想要一个具体的未来。我不知道如何实现它。

asynchronous rust types future builder
1个回答
0
投票

您可以为您创建的类型手动实现

Future
,然后将此类型命名为
<Self as IntoFuture>::IntoFuture
。今天这适用于稳定的 Rust。

use std::future::{Future, IntoFuture};
use std::pin::Pin;
use std::task::{Context, Poll};

#[derive(Default)]
struct FooFluentBuilder {
    value: i32,
}

impl FooFluentBuilder {
    fn value(mut self, value: i32) -> Self {
        self.value = value;
        self
    }

    fn send(self) -> SendFut {
        SendFut { builder: self }
    }
}

struct SendFut {
    builder: FooFluentBuilder
}

impl Future for SendFut {
    type Output = Result<i32, &'static str>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        Poll::Ready(Ok(self.get_mut().builder.value)) 
    }
}


impl IntoFuture for FooFluentBuilder {
    type Output = <<Self as IntoFuture>::IntoFuture as IntoFuture>::Output;
    type IntoFuture = SendFut;

    fn into_future(self) -> Self::IntoFuture {
        self.send()
    }
}

#[tokio::main]
async fn main() {
    let _response = FooFluentBuilder::default().value(5).send().await;
    let _response = FooFluentBuilder::default().value(5).await;
}
© www.soinside.com 2019 - 2024. All rights reserved.