为什么这个闭包的生命周期会根据看似不相关的类型而改变?

Dan*_*Dan 4 rust

用代码

fn foo<'a, 'b>(
    state: &'b mut i32,
) -> impl FnMut(&'a str) -> &'static str + 'b {
    |s| "hi"
}
Run Code Online (Sandbox Code Playgroud)

我收到一个错误

error[E0482]: lifetime of return value does not outlive the function call
112 | ) -> impl FnMut(&'a str) -> &'static str + 'b {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: the return value is only valid for the lifetime `'a` as defined on the function body at 110:9
110 | fn foo1<'a, 'b>(
    |         ^^
Run Code Online (Sandbox Code Playgroud)

但不知何故代码

fn foo2<'a, 'b>(
    state: &'b mut Option<&'a i32>,
) -> impl FnMut(&'a str) -> &'static str + 'b {
    |s| "hi"
}
Run Code Online (Sandbox Code Playgroud)

编译没有错误。为什么类型会state改变闭包的生命周期?

Fra*_*gné 7

通过 type &'b mut Option<&'a i32>,Rust 可以推断出生命周期'a: 'b'aoutlives 'b)。为了使函数签名格式良好,需要此界限。您可以显式添加此绑定以避免错误:

fn foo<'a, 'b>(
    state: &'b mut i32,
) -> impl FnMut(&'a str) -> &'static str + 'b
where
    'a: 'b,
{
    |s| "hi"
}
Run Code Online (Sandbox Code Playgroud)

但是,如果没有参数使用'a,那么'a应该是更高级别的特征边界:

fn foo<'b>(
    state: &'b mut i32,
) -> impl for<'a> FnMut(&'a str) -> &'static str + 'b {
    |s| "hi"
}
Run Code Online (Sandbox Code Playgroud)

特征系列Fn的特殊之处在于它们允许您完全省略生命周期(遵循与fn签名相同的省略规则),因此这是等效的:

fn foo<'b>(
    state: &'b mut i32,
) -> impl FnMut(&str) -> &'static str + 'b {
    |s| "hi"
}
Run Code Online (Sandbox Code Playgroud)