4

具有一个静态引用的异步函数编译:

pub async fn test_0(_a: &'static str)  {
}

具有非静态和静态引用的异步函数编译:

pub async fn test_1<'a>(_a: &'a str, _b: &'static str)  {
}

具有三个非静态引用的异步函数编译:

pub async fn test_2<'a, 'b, 'c>(_a: &'a str, _b: &'b str, _c: &'c str)  {
}

一个接受两个非静态引用和一个静态引用并返回未来编译的函数:

pub fn test_3_desugared<'a, 'b>(_a: &'a str, _b: &'b str, _c: &'static str) -> impl std::future::Future<Output=()> {
  std::future::ready(())
}

那么为什么一个带有两个非静态引用和一个静态引用的异步函数不能编译呢?

pub async fn test_3<'a, 'b>(_a: &'a str, _b: &'b str, _c: &'static str)  {
}

有问题的编译错误:

error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
  --> src/lib.rs:11:74
   |
11 | pub async fn test_3<'a, 'b>(_a: &'a str, _b: &'b str, _c: &'static str)  {
   |                                                                          ^
   |
note: hidden type `impl Future` captures lifetime smaller than the function body
  --> src/lib.rs:11:74
   |
11 | pub async fn test_3<'a, 'b>(_a: &'a str, _b: &'b str, _c: &'static str)  {
   |      

游乐场链接供参考:https ://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=4d90427b4a592ccc3b3d119a326cc401

我目前的锈版本:

$ rustc --version
rustc 1.56.1 (59eed8a2a 2021-11-01)

我在尝试将环摘要算法参数添加到已经有两个引用参数的函数时遇到了这个问题。解决方法非常简单,因为我可以将静态引用包装在一个结构中,将其传入,然后毫无问题地使用它。我只是好奇为什么会这样。

4

1 回答 1

1
“impl Future”版本编译
pub fn test_3<'a, 'b>(_a: &'a str, _b: &'b str, _c: &'static str) -> impl Future
{
   async {}
}
异步版本无法编译
pub async fn test_3<'a, 'b>(_a: &'a str, _b: &'b str, _c: &'static str)  {
}

impl Future版本编译的原因是因为_a,_b_c引用没有被未来捕获。编译器足够聪明,可以删除引用,我们可以通过函数的 HIR 看到这一点。

pub fn test_3<'a, 'b>(_a: &'a str, _b: &'b str, _c: &'static str)
 -> /*impl Trait*/ { #[lang = "from_generator"](|mut _task_context| { }) }

您可以将其与异步版本的 HIR 进行比较。在这种情况下,所有引用都被捕获。

pub async fn test_3<'a, 'b>(a: &'a str, b: &'b str, c: &'static str)
 -> /*impl Trait*/ where
 'a:'b #[lang = "from_generator"](move |mut _task_context|
                                      {
                                          let a = a;
                                          let b = b;
                                          let c = c;
                                          { let _t = { () }; _t }
                                      })

在异步版本中,函数的所有输入生命周期都在异步函数返回的未来捕获,就像这样impl Future + 'a + 'b + 'static。最后,编译器将所有这些生命周期统一为一个生命周期'0。这种统一是由成员约束算法通过“最少选择”进入一组生命周期来完成的。

对于我们的具体情况,我们得到 '0 min(['a, 'b, 'static])。问题是这个集合中没有明显的最小值,因为编译器不知道'a 和'b 之间的关系。

如果将此信息提供给编译器,则异步版本将编译

pub async fn test_3<'a, 'b>(a: &'a str, b: &'b str, c: &'static str) 
    where 'a:'b
{
   ()
}

在没有明显最小选择的情况下,另一种解决方案可能是选择 'static。在此PR#89056中进行了讨论

于 2021-11-23T23:17:46.170 回答