当在AN Option<Box<dyn Future>内实现由异步函数递归生成的流时.如何投票给Pin<Option<Box<dyn Future>>分?谢谢.

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

use futures_util::Stream;

#[pin_project::pin_project]
struct BoxedStream<T, F> {
    #[pin]
    next: Option<String>,
    #[pin]
    inner: Option<Box<dyn Future<Output = T>>>,
    //             ^--- Future generated by async function, it is an opaque type.
    generate: F,
}

impl<T, F> Stream for BoxedStream<T, F>
where
    F: Fn(String) -> (Option<String>, Box<dyn Future<Output = T>>),
{
    type Item = T;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let mut p = self.as_mut().project();
        if let Some(s) = p.inner.as_mut().as_pin_mut() {
            return match todo!("how to do it here? s.poll(cx)?") {
                result @ Poll::Ready(_) => {
                    p.inner.take();
                    result
                }
                _ => Poll::Pending,
            };
        }

        if let Some(next) = p.next.take() {
            let (next, future) = (p.generate)(next);
            p.inner.set(Some(future));
            p.next.set(next);
            return self.poll_next(cx);
        }

        Poll::Ready(None) // end
    }
}

当我只做s.poll(cx)而不是TODO时报告的错误:

error[E0599]: the method `poll` exists for struct `Pin<&mut Box<dyn Future<Output = T>>>`, but its trait bounds were not satisfied
  --> src/lib.rs:28:28
   |
28 |               return match s.poll(cx)? {
   |                              ^^^^ method cannot be called on `Pin<&mut Box<dyn Future<Output = T>>>` due to unsatisfied trait bounds
  --> /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library/core/src/future/future.rs:37:1
   |
   = note: doesn't satisfy `_: Unpin`
  --> /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library/alloc/src/boxed.rs:195:1
  ::: /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library/alloc/src/boxed.rs:198:1
   |
   = note: doesn't satisfy `_: Future`
   |
   = note: the following trait bounds were not satisfied:
           `(dyn futures_util::Future<Output = T> + 'static): Unpin`
           which is required by `Box<(dyn futures_util::Future<Output = T> + 'static)>: futures_util::Future`

推荐答案

Pin<Option<...>>没有任何意义;Pin只有在它包装的类型是一种指针时才有效.

您应该将inner存储为Option<Pin<Box<dyn Future>>>,并跳过#[pin]的 struct 固定.Option<Box<...>>本身没有理由需要被钉住(就像#[pin]做出inner: Pin<&mut Option<Box<...>>>所暗示的那样,只有内部dyn Future需要被钉住,这就是Pin<Box<...>>的意思).

同样,你也不需要也不希望next在 struct 上固定下来.因此,只需删除所有#[pin]个注释,然后从那里开始:

#[pin_project::pin_project]
struct BoxedStream<T, F> {
    next: Option<String>,
    inner: Option<Pin<Box<dyn Future<Output = T>>>>,
    generate: F,
}

impl<T, F> Stream for BoxedStream<T, F>
where
    F: Fn(String) -> (Option<String>, Pin<Box<dyn Future<Output = T>>>),
{
    type Item = T;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let p = self.as_mut().project();
        if let Some(s) = p.inner {
            return match s.as_mut().poll(cx) {
                Poll::Ready(result) => {
                    p.inner.take();
                    Poll::Ready(Some(result))
                }
                _ => Poll::Pending,
            };
        }

        if let Some(next) = p.next.take() {
            let (next, future) = (p.generate)(next);
            *p.inner = Some(future);
            *p.next = next;
            return self.poll_next(cx);
        }

        Poll::Ready(None)
    }
}

我也让你的函数类型返回Pin<Box<...>>,它可以很容易地变成Box::pin.

Rust相关问答推荐

如何在 struct 中填充缓冲区并同时显示它?

如何在不安全的代码中初始化枚举 struct

如何处理动态 struct 实例化?

这个规则关于或模式到底是什么意思?如果表达片段的类型与p_i|q_i...&q;不一致,就会形成

Box::new()会从一个堆栈复制到另一个堆吗?

在自定义序列化程序中复制serde(With)的行为

如何使用RefCell::JOYMOMTborrow 对 struct 不同字段的可变引用

通过RabbitMQ取消铁 rust 中长时间运行的人造丝任务的策略

为什么`AlternateScreen`在读取输入键时需要按Enter键?

Rust函数的返回值不能引用局部变量或临时变量

用于实现获取 struct 体 id 的特征规范

为什么 Rust 需要可变引用的显式生命周期而不是常规引用?

如何以与平台无关的方式将OsString转换为utf-8编码的字符串?

为什么 Rust 的临时值有时有参考性有时没有?

具有在宏扩展中指定的生命周期的枚举变体数据类型

我什么时候应该使用特征作为 Rust 的类型?

在运行时在 Rust 中加载字体

如何连接 Rust 中的相邻切片

为什么允许重新分配 String 而不是 *&String

带有库+多个二进制文件的Cargo 项目,二进制文件由多个文件组成?