rust 仅当函数写为闭包时才出现生存期错误

xqnpmsa8  于 2023-05-17  发布在  其他
关注(0)|答案(1)|浏览(153)

普通函数和定义为闭包的函数之间的生命周期推断似乎存在差异。考虑以下最小示例:

fn foo(f: &String) -> &str {
    f
}

fn bar() {
    |f: &String| -> &str { f };
}

编译器(Rustc 1.69.0 with --edition=2021)接受foo,但拒绝bar中的闭包(与foo相同的函数),并返回错误

error: lifetime may not live long enough
 --> clos.rs:8:33
  |
8 |     move |f: &String| -> &str { f };
  |              -           -      ^ returning this value requires that `'1` must outlive `'2`
  |              |           |
  |              |           let's call the lifetime of this reference `'2`
  |              let's call the lifetime of this reference `'1`

foo的例子中,我的理解是编译器将其去糖为

fn foo<'a>(f: &'a String) -> &'a str { ... }

为什么它不对闭包做同样的事情呢?有没有什么方法可以自己手动指定生存期(特别是,我应该把<'a>放在哪里来声明生存期)?

yrdbyhpb

yrdbyhpb1#

我认为这是因为对于函数来说,从来没有任何捕获的状态,因此输入和输出的生存期几乎总是连接的。对于封闭件,寿命可以来自环境。
您可以创建一个生成闭包的函数,它允许您使用impl Fn语法,这似乎可以正确地推断生存期,至少在本例中是这样。如果捕获任何状态,则需要将其作为参数传递给生成器函数。

fn generate() -> impl Fn(&String) -> &str {
    |f: &String| -> &str { f }
}

如果在某种情况下它不起作用,您可以使用for语法显式地指定生存期。

fn generate_for() -> impl for<'a> Fn(&'a String) -> &'a str {
    |f: &String| -> &str { f }
}

有一个每晚的功能:closure_lifetime_binder。稳定后,它将允许您将for注解添加到闭包表达式中,而不仅仅是traits。

#![feature(closure_lifetime_binder)]

fn bar_nightly() {
    for<'a> |f: &'a String| -> &'a str { f };
}

相关问题