只有在将函数写成闭包时才会出现生命周期错误。

huangapple go评论64阅读模式
英文:

Lifetime error only when function written as a closure

问题

以下是您要翻译的内容:

在正常函数和定义为闭包的函数之间存在寿命推断的差异。考虑以下最小示例:

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>以声明生命周期)?

英文:

There seems to be a difference in lifetime inference between normal functions and functions defined as closures. Consider the following minimal example:

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

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

The compiler (Rustc 1.69.0 with --edition=2021) accepts foo, but rejects the closure in bar (which is the same function as foo) with the error

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`

In the case of foo, my understanding is that the compiler desugars it to

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

Why doesn't it do the same for the closure? And is there some way I can manually specify the lifetimes myself (in particular, where would I place the <'a> to declare the lifetime)?

答案1

得分: 2

I think this is because for functions, there is never any captured state, therefore the lifetimes of the input and output are almost always connected. For closures, the lifetimes could be from the environment.

你可以创建一个生成闭包的函数,这样你可以使用 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: &'a String| -> &'a str { f }
}

这里有一个夜间特性:closure_lifetime_binder。当它稳定下来时,它将允许你在闭包表达式中添加 for 注释,而不仅仅是在特性中。

#![feature(closure_lifetime_binder)]

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

I think this is because for functions, there is never any captured state, therefore the lifetimes of the input and output are almost always connected. For closures, the lifetimes could be from the environment.

You can make a function that generates the closure, which lets you use impl Fn syntax, which seems to infer lifetimes correctly, at least in this case. If you capture any state, you will need to pass that as an argument to the generator function.

fn generate() -&gt; impl Fn(&amp;String) -&gt; &amp;str {
    |f: &amp;String| -&gt; &amp;str { f }
}

If it doesn't work for a certain case, you can use for syntax to specify the lifetimes explicitly.

fn generate_for() -&gt; impl for&lt;&#39;a&gt; Fn(&amp;&#39;a String) -&gt; &amp;&#39;a str {
    |f: &amp;String| -&gt; &amp;str { f }
}

There's a nightly feature for this: closure_lifetime_binder. When stabilized, it will allow you to add for annotations to closure expressions instead of only to traits.

#![feature(closure_lifetime_binder)]

fn bar_nightly() {
    for&lt;&#39;a&gt; |f: &amp;&#39;a String| -&gt; &amp;&#39;a str { f };
}

huangapple
  • 本文由 发表于 2023年5月15日 03:15:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76249278.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定