gpt4 book ai didi

asynchronous - 相互调用的递归异步函数 : cycle detected

转载 作者:行者123 更新时间:2023-12-05 04:19:41 27 4
gpt4 key购买 nike

以下代码是我尝试编写的代码的简化版本。

来自 Go,我发现处理相互调用的递归函数有点困难。

首先尝试(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

所以我尝试了第二个版本(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。对于递归异步函数,生成的状态机类型必须包含自身,以便您获得无限大小的类型。所以你必须把它装箱。

然而,编译器限制目前不允许仅装箱。您必须将递归函数转换为非异步函数,该函数返回一个装箱的异步 block 。

编译并运行:

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);
}

关于asynchronous - 相互调用的递归异步函数 : cycle detected,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74737595/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com