我认为这个问题一般都是关于生命周期的,但我特别是因为你不能写出他们的类型而对闭包有困难。
这个例子有点做作 - 我刚刚开始学习Rust,这是我一直挂断的东西。
此程序无法编译:
fn main () {
let mut list: Vec<&Fn() -> i32> = Vec::new();
{
list.push(&|| 1);
}
}
由于:
src/main.rs:5:25: 5:24 error: borrowed value does not live long enough
src/main.rs:5 list.push(&|| 1);
^~~~
src/main.rs:2:50: 7:2 note: reference must be valid for the block suffix following statement 0 at 2:49...
src/main.rs:2 let mut list: Vec<&Fn() -> i32> = Vec::new();
src/main.rs:3
src/main.rs:4 {
src/main.rs:5 list.push(&move || 1);
src/main.rs:6 }
src/main.rs:7 }
src/main.rs:5:9: 5:26 note: ...but borrowed value is only valid for the statement at 5:8
src/main.rs:5 list.push(&|| 1);
^~~~~~~~~~~~~~~~~
src/main.rs:5:9: 5:26 help: consider using a `let` binding to increase its lifetime
src/main.rs:5 list.push(&|| 1);
^~~~~~~~~~~~~~~~~
我从这个错误中收集到的是封闭的生命周期仅限于
块内的语句,但它需要为整个main
生存。
我知道(或者,我认为)将闭包传递给push
作为引用意味着push
只是借用闭包,并且所有权将返回到块。如果我可以将闭包赋予push
(即如果push
取得闭包的所有权),则此代码将起作用,但由于闭包的大小不合适,我必须将其作为参考传递。< / p>
是吗?如何使这段代码有效?
答案 0 :(得分:8)
您要问的有两件事:
第一个问题是通过NOT指定typename来解决的,让rust类型推断可以正常工作。
let mut list: Vec<_> = Vec::new();
第二个问题是通过不试图延长关闭时间来解决问题,而是通过实现&#34;价值&#34;所以你可以移动它。这会强制您的闭包不引用任何内容,但拥有所有捕获的值。
for i in 0..10 {
list.push(move || i);
}
现在这给了我们一个新问题。如果我们为Vec
添加不同的闭包,那么这些类型就不会匹配。因此,要实现这一点,我们需要打开封闭。
fn main () {
let mut list: Vec<Box<Fn() -> i32>> = Vec::new();
for i in 0..10 {
list.push(Box::new(move|| i));
}
{
list.push(Box::new(move|| 42));
}
}
答案 1 :(得分:6)
借用不拥有他们指向的东西。你的问题是你借用了一个临时,它会在借来后立即停止存在,因为你还没有将它存储在任何地方。如果它有帮助,考虑借用不借用值,他们借用存储,而临时只有暂时存储。
如果您希望在任何给定时间内借用某些东西,必须从存储中借用至少那么久。在这种情况下,因为您希望将借用存储在Vec
中,这意味着您借用的任何存储空间必须比Vec
更长。因此:
fn main () {
let closure;
let mut list: Vec<&Fn() -> i32> = Vec::new();
{
closure = || 1;
list.push(&closure);
}
}
请注意,closure
是在 list
之前定义的。在Rust中,值在其作用域的末尾以反向词法顺序删除,因此在 list
之后定义的任何变量必然会在它之前被删除,从而导致包含list
无效的指针。
如果要推送多个闭包,则每个闭包都需要一个单独的变量。
预防可能的问题&#34;我的实际问题不是这么简单&#34;附录(:P):如果您需要返回list
或以某种方式将其持续到单个函数调用之外,请注意无法扩展借用。在这种情况下,您需要做的是将list
更改为拥有的的矢量,盒装闭包(即 Vec<Box<Fn() -> i32>>
)。