我写了以下内容来测试闭包:
fn main() {
let captured_val = "a captured value".to_string();
let closure_parameter = "a parameter value".to_string();
let mut ct = ClosureTest {
cls: |closure_parameter| &captured_val,
};
println!("{}", (ct.cls)(&closure_parameter));
}
struct ClosureTest<T>
where
T: FnMut(&str) -> &str,
{
cls: T,
}
我得到以下编译错误:
error[E0373]: closure may outlive the current function, but it borrows `captured_val`, which is owned by the current function
--> src/main.rs:6:14
|
6 | cls: |closure_parameter| &captured_val,
| ^^^^^^^^^^^^^^^^^^^ ------------ `captured_val` is borrowed here
| |
| may outlive borrowed value `captured_val`
help: to force the closure to take ownership of `captured_val` (and any other referenced variables), use the `move` keyword
|
6 | cls: move |closure_parameter| &captured_val,
| ^^^^^^^^^^^^^^^^^^^^^^^^
我在struct中添加了一个生命周期参数,它编译并运行良好:
struct ClosureTest<'a, T>
where
T: FnMut(&str) -> &'a str,
{
cls: T,
}
两个变量( captured_val
和 closure_parameter
)都在相同的范围内,但似乎编译器没有看到它们具有相同的生命周期而没有生命周期参数 'a
我添加到 ClosureTest<T>
. 这是因为Rust的封闭期终生推理?
我不明白我收到的错误消息中的第一行:
error[E0373]: closure may outlive the current function, but it borrows `captured_val`, which is owned by the current function
封闭怎么能比现在的功能更长久?闭包是在当前函数中定义的,所以我认为闭包将在当前函数的末尾消失 .
错误消息的真正含义是什么?为什么它会像我一样添加生命周期参数来解决?
1 回答
The short version: 添加显式生命周期注释使 guarantee 关于
ClosureTest
,如果没有它,则不一定暗示 .长版
假设你这样做:
在标有
!!!
的行上,请注意ct
作为返回值移出函数 . 该对象现在'lives'在main
中,但它包含对do_something
结束时删除的内容的引用 .ct.cls
正在返回对captured_val
的引用,如果将ct
移出函数,该引用将不再存在 .通过修改
ClosureTest
以包含生命周期,您将说明以下内容:一个
ClosureTest
对象obj
有一些生命周期'a
obj.cls
返回的str
引用在obj
上定义为'a
的整个生命周期内生存,如果不再因此,
obj.cls
返回的任何引用都与返回它的ClosureTest
具有相同的范围 .obj
将与其闭包引用的对象同时删除,或者更快 . 换句话说,任何ClosureType<'a, T> where T: FnMut(&str) -> &'a str
只能在对象T
的返回引用存在时生存,并且必须在删除该对象时删除 .借用检查器不会对原始值感到恼火,因为
ct
和captured_value
具有不同的生命周期,这是因为它们可能具有不同的生命周期 - 因此'may'中'可能比借来的值更长captured_val
' . 当你在你的例子中添加了lifetime参数时,借用检查器现在可以确认只有captured_val
和ct
一样存在它才能进行编译(它会在main
结束时被删除) .