此代码编译:
async fn foo(_: impl Iterator<Item = &u32>) {}
但是,删除async
,它不再工作:
fn foo(_: impl Iterator<Item = &u32>) {}
相反,它导致:
error[E0106]: missing lifetime specifier
--> src/lib.rs:1:32
|
1 | fn foo(_: impl Iterator<Item = &u32>) {}
| ^ expected named lifetime parameter
|
help: consider introducing a named lifetime parameter
|
1 | fn foo<'a>(_: impl Iterator<Item = &'a u32>) {}
| ^^^^ ^^^
(Playground)
为什么async
和非async
函数在生命周期省略方面存在差异?这对我来说毫无意义。看来非async
的情况下也可以很容易地遗漏寿命。它只是引入了另一个匿名输入生命周期。
1条答案
按热度按时间vngu2lb81#
在Rust中,函数参数中引用的生命周期有时会被省略,这意味着它们可以被忽略,编译器会自动推断它们。然而,这种自动推理有一些局限性,它并不适用于所有可能的场景。
对于非
async
函数,生存期省略遵循三条规则:1.输入位置中的每个省略的寿命变成不同的寿命参数。
1.如果只有一个输入生存期,则将该生存期分配给所有省略的输出生存期。
1.如果有多个输入生存期,但其中一个是
&self
或&mut self
,则self的生存期被分配给所有省略的输出生存期。在
fn foo(_: impl Iterator<Item = &u32>) {}
的情况下,&u32
中有一个省略的生存期,它不直接在函数的输入中(它在trait的关联类型中)。这与上面的任何规则都不匹配,因此编译器无法推断出省略的生存期,因此出现了错误。说到
async fn foo(_: impl Iterator<Item = &u32>) {}
,它编译的原因与async fn
的脱糖过程有关。当您声明async fn
时,Rust编译器将其转换为返回Future
的非异步函数。你的函数的实际签名是这样的:在这种去糖形式中,
&u32
的生存期与输出future的生存期相关联,这允许编译器根据上述规则推断出省略的生存期。在编写
async fn
时,这种转换对您来说是透明的,但它确实会影响函数处理生存期的方式。这可能有点违反直觉,但这是Rust的生存期省略规则的设计方式以及async fn
的实现方式的结果。因此,您看到的差异是由于
async fn
经历的省略规则和转换的组合,而不是因为async
和非async
函数之间处理生命周期的固有差异。