rust 我可以在递归函数中使用await吗?

arknldoa  于 6个月前  发布在  其他
关注(0)|答案(2)|浏览(105)
pub async fn send_and_expect(&mut self, request: rtsp_types::Request<Body>, retrying: bool) -> std::result::Result<rtsp_types::Response<Body>, ClientActionError> {

字符串
我明白了:

recursion in an `async fn` requires boxing
    
recursive `async fn`
    
note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`rustc(E0733)


我找到了https://rust-lang.github.io/async-book/07_workarounds/04_recursion.html,但它是一个不使用async的函数。
这里应该怎么走呢?
我找到了Why recursive async functions require 'static parameters in Rust?,并将函数改为

pub fn send_and_expect(&mut self, request: rtsp_types::Request<Body>, retrying: bool) 
-> Pin<Box<dyn Future <Output = std::result::Result<rtsp_types::Response<Body>, ClientActionError>>>> {


但是现在我不能在我的函数里面使用await了。还有,我怎么返回东西呢?
举例来说:

return Box::pin(Err(ClientActionError::CSeqMissing))


行不通

更新

根据下面的答案,我在递归调用中得到了这个:

194 |         }.boxed()
    |           ^^^^^ future created by async block is not `Send`
    |
    = help: the trait `std::marker::Send` is not implemented for `dyn futures::Future<Output = std::result::Result<rtsp_types::Response<Body>, ClientActionError>>`
note: future is not `Send` as it awaits another future which is not `Send`
   --> src/client.rs:170:36
    |
170 | ...                   return self.send_and_expect(request.clone(), true).await;
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `Pin<Box<dyn futures::Future<Output = std::result::Result<rtsp_types::Response<Body>, ClientActionError>>>>`, which is not `Send`

更新2:

error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> src/client.rs:156:20
    |
154 |       pub fn send_and_expect(&mut self, request: rtsp_types::Request<Body>, retrying: bool) 
    |                              --------- this data with an anonymous lifetime `'_`...
155 |       -> Pin<Box<dyn Future<Output = std::result::Result<rtsp_types::Response<Body>, ClientActionError>>+ Send>> {    
156 |           async move {
    |  ____________________^
157 | |             let expected_cseq_header_value = rtsp_types::HeaderName::from_static_str("cseq").unwrap();
158 | |             let expected_cseq = request.header(&expected_cseq_header_value);
159 | |             let expected_cseq = match expected_cseq {
...   |
193 | |             Err(ClientActionError::Teardown)
194 | |         }.boxed()
    | |_________^ ...is captured here, requiring it to live as long as `'static`
    |
help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
    |
155 |     -> Pin<Box<dyn Future<Output = std::result::Result<rtsp_types::Response<Body>, ClientActionError>>+ Send + '_>> {    
    |                                                                                                              ^^^^

mcvgt66p

mcvgt66p1#

我找到了[...],但它是一个不使用async的函数。
是的。你应该仔细看看代码。原始函数肯定是async

async fn recursive() {
    recursive().await;
    recursive().await;
}

字符串
.但是现在我不能在函数中使用await
如果你按照修复建议创建一个async {}块,你就可以:

use futures::future::{BoxFuture, FutureExt};

fn recursive() -> BoxFuture<'static, ()> {
    async move {
        recursive().await; // you can use await here
        recursive().await;
    }.boxed()
}


这个想法很简单,因为async/await的返回类型需要被装箱,而不是impl Future。所以修复方法是创建一个async {}块,在其中正常运行函数,然后将其装箱以返回它。这避免了嵌套的async/await函数被单态化在一起所导致的问题。
因此,您应该能够:

pub fn send_and_expect(&mut self, request: rtsp_types::Request<Body>, retrying: bool) 
-> Pin<Box<dyn Future<Output = std::result::Result<rtsp_types::Response<Body>, ClientActionError>> + Send>> {
                                                                                                // ^^^^^^
    async move {
        // put your original code here
    }.boxed()
}


还有,我怎么退东西?
你可以通过async块中的最后一个表达式返回正常的东西,或者你可以使用return。你应该和一个正确的async函数一样,不要担心Box::pin(...)
如果您需要Future来满足任何其他trait边界(SendSyncUnpin等),那么您可以沿着dyn Future<...>来指定它
返回类型要求dyn Future<Output = ...> + Send使用.boxed()
如果async块的内容不能被设置为Send,你可以像这样手动设置(尽管大多数运行时都希望Future s是Send,所以你很难使用它):

fn recursive() -> Pin<Box<dyn Future<Output = ()>>> {
    Box::pin(async move {
        recursive().await;
        recursive().await;
    })
}

ars1skjm

ars1skjm2#

另外,为了帮助其他人,有一个crate提供了一个宏来自动重写整个复杂的函数:https://docs.rs/async-recursion/latest/async_recursion

相关问题