英文:
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() -> impl Fn(&String) -> &str {
|f: &String| -> &str { f }
}
If it doesn't work for a certain case, you can use for
syntax to specify the lifetimes explicitly.
fn generate_for() -> impl for<'a> Fn(&'a String) -> &'a str {
|f: &String| -> &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<'a> |f: &'a String| -> &'a str { f };
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论