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

Gat*_*ito 7 rust

pub async fn send_and_expect(&mut self, request: rtsp_types::Request<Body>, retrying: bool) -> std::result::Result<rtsp_types::Response<Body>, ClientActionError> {
Run Code Online (Sandbox Code Playgroud)

我得到:

pub async fn send_and_expect(&mut self, request: rtsp_types::Request<Body>, retrying: bool) -> std::result::Result<rtsp_types::Response<Body>, ClientActionError> {
Run Code Online (Sandbox Code Playgroud)

我找到了https://rust-lang.github.io/async-book/07_workarounds/04_recursion.html但它适用于不使用async.

这里应该走什么路?

我发现为什么递归异步函数需要“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>>>> {
Run Code Online (Sandbox Code Playgroud)

但现在我不能await在我的函数中使用。另外,我该如何退货?

例如:

return Box::pin(Err(ClientActionError::CSeqMissing))
Run Code Online (Sandbox Code Playgroud)

行不通

更新

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

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`
Run Code Online (Sandbox Code Playgroud)

更新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 + '_>> {    
    |                                                                                                              ^^^^
Run Code Online (Sandbox Code Playgroud)

kmd*_*eko 2

我找到了 [...] 但它是针对不使用async.

是的,它确实。您应该仔细查看代码。原来的函数肯定是async

async fn recursive() {
    recursive().await;
    recursive().await;
}
Run Code Online (Sandbox Code Playgroud)

...但现在我不能await在我的函数中使用。

async {}如果您按照修复建议进行阻止,则可以:

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

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

这个想法只是需要装箱异步返回类型而不是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()
}
Run Code Online (Sandbox Code Playgroud)

另外,我该如何退货?

您可以通过块中的最后一个表达式正常返回内容async,也可以使用return. 您应该与正确功能相同async,不用担心Box::pin(...).

如果您需要Future满足任何其他特征边界(SendSyncUnpin等),那么您可以将其与dyn Future<...>


返回类型需要dyn Future<Output = ...> + Send使用.boxed().

async如果无法创建块的内容Send,您可以像这样手动完成(尽管大多数运行时都希望Futures 如此Send,所以您很难使用它):

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