将AsyncRead的“self”包装起来具有匿名生命周期“' _”,但它需要满足“'static”生命周期要求

3

我正在尝试将 AsyncRead 包装在另一个 AsyncRead 中(并对其进行一些数据处理)。但是,在尝试存储 .read()Future 时,我遇到了生命周期问题:self has an anonymous lifetime '_ but it needs to satisfy a 'static lifetime requirement

代码:

pub struct AsyncReadWrap {
    input: Pin<Box<dyn AsyncRead + 'static>>,
    future: Option<Pin<Box<dyn Future<Output = std::io::Result<usize>>>>>
}

impl AsyncReadWrap {
    pub fn new(input: impl AsyncRead + Unpin + 'static) -> AsyncReadWrap {
        AsyncReadWrap {
            input: Box::pin(input),
            future: None
        }
    }
}

impl AsyncRead for AsyncReadWrap {
    fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>) -> Poll<std::io::Result<()>> {
        
        let mut buffer = [0u8; 2048];
        let future = self.input.as_mut().read(&mut buffer);
        self.future = Some(Box::pin(future));
       
        Poll::Pending
    }
}

我对异步操作还很陌生,感到奇怪的是在 poll 函数中没有简单的方法可以使用 await。谢谢。

1个回答

2
您不能从 poll 函数调用 await,因为 await 可能会多次调用 poll 并在其间将控制权返回执行器。单个 poll 调用只能产生一个 yield,并且只能通过另一个 poll 调用恢复。轮询和 futures 是 async/await 的构建块——在使用较低级别的实现时,您无法使用更高级别的抽象。
您当前代码的问题在于,您的结构体是自引用的。 input.read() 返回一个可能从 input 借用的 future:
// `Read` borrows from `self` and `buf`
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> 

你不能将返回的 Future 存储在结构体中,因为 在同一个结构体中同时存储值和对该值的引用是有问题的

要创建一个 AsyncRead 包装器,你可以调用内部 AsyncReadpoll_read 方法。当 poll_read 返回 Ready 时,缓冲区将被读取值填充,接着你可以对其进行数据处理:

impl AsyncRead for AsyncReadWrap {
    fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, mut buf: &mut ReadBuf<'_>) -> Poll<std::io::Result<()>> {
        match self.input.as_mut().poll_read(cx, &mut buf) {
            Poll::Ready(res) => {
                // do stuff with `buf`
                Poll::Ready(res)
            },
            Poll::Pending => Poll::Pending
        }
    }
}

poll_read函数内执行更多的async操作将变得复杂,因为您必须跟踪您的AsyncRead实现将处于的多个状态。 async/await是对较低级别的未来状态机的抽象。如果您不一定需要实现AsyncRead,则可以完全避免较低级别的未来,并使其成为一个async方法:
pub async fn read(mut input: impl AsyncRead + Unpin) -> Vec<u8> {
    let mut buf = [0u8; 1024];
    input.read(&mut buf).await;
    // ...
    buf.to_vec()
}

如果您选择走低级路线,这里有一些有用的资源:

1
谢谢您的解释,帮助我理解了这个问题。我之前已经尝试过poll_read,但是由于某些原因它不能读取多次。可能是我的代码有bug。如果我的流程解决方法失败了,我会再试一次。 - Makalone LOgman
@MakaloneLOgman 期货交易手动编写难度大,由于流程不直观,容易出错。另外,请注意,如果返回 Poll::Pending,执行器将不会再次轮询您,除非您告诉它唤醒您。如果您选择采用更低级别的异步实现,我会在答案中提供一些资源链接以帮助您入门。 - Ibraheem Ahmed
是的,我现在正在尝试,任何帮助都会有用。 - Makalone LOgman
有趣的是,在这些有用的资源中,仅有五个独特单词之一实际上是“suffering”,而其他两个则是“Async”和“Await”。 - oliver
@oliver 嗯,低级别的异步 Rust 确实很难,这是毫无疑问的。只是因为 async/await 还非常新,许多较低级别的细节仍然向初学者公开。 - Ibraheem Ahmed
我害怕打开它:/ - oliver

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接