以下代码是我try 编写的代码的简化版本.

来自GO的我发现,处理递归函数之间的相互调用有些困难.

第一次try (REPL on Playground here):

#[derive(Debug)]
struct Team {
    id: String
}

impl Team {
    pub async fn query(with_coach: bool) -> Result<Option<Team>, ()> {
        if with_coach {
            let coach = Coach::query(false).await?;
            
            dbg!(coach);
        }

        Ok(None)
    }
}

#[derive(Debug)]
struct Coach {
    id: String
}

impl Coach {
    pub async fn query(with_team: bool) -> Result<Option<Coach>, ()> {
        if with_team {
            let team = Team::query(false).await?;
            
            dbg!(team);
        }
        
        Ok(None)
    }
}

#[tokio::main]
async fn main() {
    let team = Team::query(true).await;

    dbg!(team);
}

错误是:

error[E0733]: recursion in an `async fn` requires boxing
 --> src/main.rs:7:45
  |
7 |     pub async fn query(with_coach: bool) -> Result<Option<Team>, ()> {
  |                                             ^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
  |
  = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
  = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion

error[E0733]: recursion in an `async fn` requires boxing
  --> src/main.rs:24:44
   |
24 |     pub async fn query(with_team: bool) -> Result<Option<Coach>, ()> {
   |                                            ^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn`
   |
   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion

所以我try 了第二个版本(REPL on Playground here):

use std::{future::Future, pin::Pin};

#[derive(Debug)]
struct Team {
    id: String,
}

impl Team {
    pub async fn query<'a>(
        id: &'a str,
        with_coach: bool,
    ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
        Box::pin(async move {
            if with_coach {
                let coach = Coach::query("", false).await.await?;

                dbg!(coach);
            }

            Ok(None)
        })
    }
}

#[derive(Debug)]
struct Coach {
    id: String,
}

impl Coach {
    pub async fn query<'a>(
        id: &'a str,
        with_team: bool,
    ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
        Box::pin(async move {
            if with_team {
                let team = Team::query("", false).await.await?;

                dbg!(team);
            }

            Ok(None)
        })
    }
}

#[tokio::main]
async fn main() {
    let team = Team::query("", true).await.await;

    dbg!(team);
}

但正如您可以想象的那样,有一个(非常奇怪的)错误:

error[E0391]: cycle detected when computing type of `<impl at src/main.rs:8:1: 8:10>::query::{opaque#0}`
  --> src/main.rs:12:10
   |
12 |     ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: ...which requires borrow-checking `<impl at src/main.rs:8:1: 8:10>::query`...
  --> src/main.rs:9:5
   |
9  | /     pub async fn query<'a>(
10 | |         id: &'a str,
11 | |         with_coach: bool,
12 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
   | |____________________________________________________________________________^
note: ...which requires processing `<impl at src/main.rs:8:1: 8:10>::query`...
  --> src/main.rs:9:5
   |
9  | /     pub async fn query<'a>(
10 | |         id: &'a str,
11 | |         with_coach: bool,
12 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
   | |____________________________________________________________________________^
note: ...which requires processing MIR for `<impl at src/main.rs:8:1: 8:10>::query`...
  --> src/main.rs:9:5
   |
9  | /     pub async fn query<'a>(
10 | |         id: &'a str,
11 | |         with_coach: bool,
12 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
   | |____________________________________________________________________________^
note: ...which requires unsafety-checking `<impl at src/main.rs:8:1: 8:10>::query`...
  --> src/main.rs:9:5
   |
9  | /     pub async fn query<'a>(
10 | |         id: &'a str,
11 | |         with_coach: bool,
12 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
   | |____________________________________________________________________________^
note: ...which requires building MIR for `<impl at src/main.rs:8:1: 8:10>::query`...
  --> src/main.rs:9:5
   |
9  | /     pub async fn query<'a>(
10 | |         id: &'a str,
11 | |         with_coach: bool,
12 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
   | |____________________________________________________________________________^
note: ...which requires building THIR for `<impl at src/main.rs:8:1: 8:10>::query`...
  --> src/main.rs:9:5
   |
9  | /     pub async fn query<'a>(
10 | |         id: &'a str,
11 | |         with_coach: bool,
12 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
   | |____________________________________________________________________________^
note: ...which requires type-checking `<impl at src/main.rs:8:1: 8:10>::query`...
  --> src/main.rs:13:9
   |
13 | /         Box::pin(async move {
14 | |             if with_coach {
15 | |                 let coach = Coach::query("", false).await.await?;
16 | |
...  |
20 | |             Ok(None)
21 | |         })
   | |__________^
   = note: ...which requires evaluating trait selection obligation `for<'r, 's, 't0> {core::future::ResumeTy, bool, &'r str, impl for<'s> core::future::future::Future<Output = core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = core::result::Result<core::option::Option<Coach>, ()>> + core::marker::Send + 's)>>>, (), core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = core::result::Result<core::option::Option<Coach>, ()>> + core::marker::Send + 't0)>>}: core::marker::Send`...
note: ...which requires computing type of `<impl at src/main.rs:30:1: 30:11>::query::{opaque#0}`...
  --> src/main.rs:34:10
   |
34 |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires borrow-checking `<impl at src/main.rs:30:1: 30:11>::query`...
  --> src/main.rs:31:5
   |
31 | /     pub async fn query<'a>(
32 | |         id: &'a str,
33 | |         with_team: bool,
34 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   | |_____________________________________________________________________________^
note: ...which requires processing `<impl at src/main.rs:30:1: 30:11>::query`...
  --> src/main.rs:31:5
   |
31 | /     pub async fn query<'a>(
32 | |         id: &'a str,
33 | |         with_team: bool,
34 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   | |_____________________________________________________________________________^
note: ...which requires processing MIR for `<impl at src/main.rs:30:1: 30:11>::query`...
  --> src/main.rs:31:5
   |
31 | /     pub async fn query<'a>(
32 | |         id: &'a str,
33 | |         with_team: bool,
34 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   | |_____________________________________________________________________________^
note: ...which requires unsafety-checking `<impl at src/main.rs:30:1: 30:11>::query`...
  --> src/main.rs:31:5
   |
31 | /     pub async fn query<'a>(
32 | |         id: &'a str,
33 | |         with_team: bool,
34 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   | |_____________________________________________________________________________^
note: ...which requires building MIR for `<impl at src/main.rs:30:1: 30:11>::query`...
  --> src/main.rs:31:5
   |
31 | /     pub async fn query<'a>(
32 | |         id: &'a str,
33 | |         with_team: bool,
34 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   | |_____________________________________________________________________________^
note: ...which requires building THIR for `<impl at src/main.rs:30:1: 30:11>::query`...
  --> src/main.rs:31:5
   |
31 | /     pub async fn query<'a>(
32 | |         id: &'a str,
33 | |         with_team: bool,
34 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   | |_____________________________________________________________________________^
note: ...which requires type-checking `<impl at src/main.rs:30:1: 30:11>::query`...
  --> src/main.rs:35:9
   |
35 | /         Box::pin(async move {
36 | |             if with_team {
37 | |                 let team = Team::query("", false).await.await?;
38 | |
...  |
42 | |             Ok(None)
43 | |         })
   | |__________^
   = note: ...which requires evaluating trait selection obligation `for<'r, 's, 't0> {core::future::ResumeTy, bool, &'r str, impl for<'s> core::future::future::Future<Output = core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = core::result::Result<core::option::Option<Team>, ()>> + core::marker::Send + 's)>>>, (), core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = core::result::Result<core::option::Option<Team>, ()>> + core::marker::Send + 't0)>>}: core::marker::Send`...
   = note: ...which again requires computing type of `<impl at src/main.rs:8:1: 8:10>::query::{opaque#0}`, completing the cycle
note: cycle used when checking item types in top-level module
  --> src/main.rs:1:1
   |
1  | / use std::{future::Future, pin::Pin};
2  | |
3  | | #[derive(Debug)]
4  | | struct Team {
...  |
51 | |     dbg!(team);
52 | | }
   | |_^

error[E0391]: cycle detected when computing type of `<impl at src/main.rs:8:1: 8:10>::query::{opaque#0}`
  --> src/main.rs:12:10
   |
12 |     ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: ...which requires borrow-checking `<impl at src/main.rs:8:1: 8:10>::query`...
  --> src/main.rs:9:5
   |
9  | /     pub async fn query<'a>(
10 | |         id: &'a str,
11 | |         with_coach: bool,
12 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
   | |____________________________________________________________________________^
note: ...which requires processing `<impl at src/main.rs:8:1: 8:10>::query`...
  --> src/main.rs:9:5
   |
9  | /     pub async fn query<'a>(
10 | |         id: &'a str,
11 | |         with_coach: bool,
12 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
   | |____________________________________________________________________________^
note: ...which requires processing MIR for `<impl at src/main.rs:8:1: 8:10>::query`...
  --> src/main.rs:9:5
   |
9  | /     pub async fn query<'a>(
10 | |         id: &'a str,
11 | |         with_coach: bool,
12 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
   | |____________________________________________________________________________^
note: ...which requires unsafety-checking `<impl at src/main.rs:8:1: 8:10>::query`...
  --> src/main.rs:9:5
   |
9  | /     pub async fn query<'a>(
10 | |         id: &'a str,
11 | |         with_coach: bool,
12 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
   | |____________________________________________________________________________^
note: ...which requires building MIR for `<impl at src/main.rs:8:1: 8:10>::query`...
  --> src/main.rs:9:5
   |
9  | /     pub async fn query<'a>(
10 | |         id: &'a str,
11 | |         with_coach: bool,
12 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
   | |____________________________________________________________________________^
note: ...which requires building THIR for `<impl at src/main.rs:8:1: 8:10>::query`...
  --> src/main.rs:9:5
   |
9  | /     pub async fn query<'a>(
10 | |         id: &'a str,
11 | |         with_coach: bool,
12 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
   | |____________________________________________________________________________^
note: ...which requires type-checking `<impl at src/main.rs:8:1: 8:10>::query`...
  --> src/main.rs:13:9
   |
13 | /         Box::pin(async move {
14 | |             if with_coach {
15 | |                 let coach = Coach::query("", false).await.await?;
16 | |
...  |
20 | |             Ok(None)
21 | |         })
   | |__________^
   = note: ...which requires evaluating trait selection obligation `for<'r, 's, 't0> {core::future::ResumeTy, bool, &'r str, impl for<'s> core::future::future::Future<Output = core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = core::result::Result<core::option::Option<Coach>, ()>> + core::marker::Send + 's)>>>, (), core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = core::result::Result<core::option::Option<Coach>, ()>> + core::marker::Send + 't0)>>}: core::marker::Send`...
note: ...which requires computing type of `<impl at src/main.rs:30:1: 30:11>::query::{opaque#0}`...
  --> src/main.rs:34:10
   |
34 |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires borrow-checking `<impl at src/main.rs:30:1: 30:11>::query`...
  --> src/main.rs:31:5
   |
31 | /     pub async fn query<'a>(
32 | |         id: &'a str,
33 | |         with_team: bool,
34 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   | |_____________________________________________________________________________^
note: ...which requires processing `<impl at src/main.rs:30:1: 30:11>::query`...
  --> src/main.rs:31:5
   |
31 | /     pub async fn query<'a>(
32 | |         id: &'a str,
33 | |         with_team: bool,
34 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   | |_____________________________________________________________________________^
note: ...which requires processing MIR for `<impl at src/main.rs:30:1: 30:11>::query`...
  --> src/main.rs:31:5
   |
31 | /     pub async fn query<'a>(
32 | |         id: &'a str,
33 | |         with_team: bool,
34 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   | |_____________________________________________________________________________^
note: ...which requires unsafety-checking `<impl at src/main.rs:30:1: 30:11>::query`...
  --> src/main.rs:31:5
   |
31 | /     pub async fn query<'a>(
32 | |         id: &'a str,
33 | |         with_team: bool,
34 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   | |_____________________________________________________________________________^
note: ...which requires building MIR for `<impl at src/main.rs:30:1: 30:11>::query`...
  --> src/main.rs:31:5
   |
31 | /     pub async fn query<'a>(
32 | |         id: &'a str,
33 | |         with_team: bool,
34 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   | |_____________________________________________________________________________^
note: ...which requires building THIR for `<impl at src/main.rs:30:1: 30:11>::query`...
  --> src/main.rs:31:5
   |
31 | /     pub async fn query<'a>(
32 | |         id: &'a str,
33 | |         with_team: bool,
34 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   | |_____________________________________________________________________________^
note: ...which requires type-checking `<impl at src/main.rs:30:1: 30:11>::query`...
  --> src/main.rs:31:5
   |
31 | /     pub async fn query<'a>(
32 | |         id: &'a str,
33 | |         with_team: bool,
34 | |     ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
   | |_____________________________________________________________________________^
   = note: ...which again requires computing type of `<impl at src/main.rs:8:1: 8:10>::query::{opaque#0}`, completing the cycle
note: cycle used when checking item types in top-level module
  --> src/main.rs:1:1
   |
1  | / use std::{future::Future, pin::Pin};
2  | |
3  | | #[derive(Debug)]
4  | | struct Team {
...  |
51 | |     dbg!(team);
52 | | }
   | |_^

这一切意味着什么?

我如何修复此代码?

推荐答案

你们很接近了.当你返回盒装future 时,你只是不需要异步化.更多细节herehere

Async FN创建一个状态机类型,其中包含每个子Future Being.对于递归异步函数,生成的状态机类型必须包含其自身,因此您可以获得无限大小的类型.所以你必须把它装进盒子里.

然而,编译器的限制目前并不允许只进行装箱.你必须把递归函数变成一个非异步函数,它返回一个盒装的异步块.

这段代码编译并运行:

use std::{future::Future, pin::Pin};

#[derive(Debug)]
struct Team {
    id: String,
}

impl Team {
    pub fn query<'a>(
        id: &'a str,
        with_coach: bool,
    ) -> Pin<Box<dyn Future<Output = Result<Option<Team>, ()>> + Send + 'a>> {
        Box::pin(async move {
            if with_coach {
                let coach = Coach::query("", false).await?;

                dbg!(coach);
            }

            Ok(None)
        })
    }
}

#[derive(Debug)]
struct Coach {
    id: String,
}

impl Coach {
    pub fn query<'a>(
        id: &'a str,
        with_team: bool,
    ) -> Pin<Box<dyn Future<Output = Result<Option<Coach>, ()>> + Send + 'a>> {
        Box::pin(async move {
            if with_team {
                let team = Team::query("", false).await?;

                dbg!(team);
            }

            Ok(None)
        })
    }
}

#[tokio::main]
async fn main() {
    let team = Team::query("", true).await;

    dbg!(team);
}

Rust相关问答推荐

Rust,polars CSV:有没有一种方法可以从impll BufRead(或任何字节迭代器)中读取CSV?

把Vector3变成Vector4的绝妙方法

Rust中的相互递归特性与默认实现

为什么我的梅森素数代码的指数越大,速度就越快?

如何使用字符串迭代器执行查找?

在Rust中宏的表达式中提取对象

在Rust中显式装箱受生存期限制的转换闭包

如何将像烫手山芋一样不透明的值从一个Enum构造函数移动到下一个构造函数?

同时从不同线程调用DLL的不同函数会出现分段错误或产生STATUS_STACK_BUFFER_OVERRUN

Rust&;Tokio:如何处理更多的信号,而不仅仅是SIGINT,即SIGQUE?

如何从ruust中的fig.toml中读取?

如何将带有嵌套borrow /NLL 的 Rust 代码提取到函数中

如何返回 struct 体中向量的切片

unwrap 选项类型出现错误:无法移出共享引用后面的*foo

为什么我们有两种方法来包含 serde_derive?

rust tokio::spawn 在 mutexguard 之后等待

在 RefCell 上borrow

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

基于名称是否存在的条件编译

为什么当borrow 变量发生变化时,borrow 变量不会改变?