如何声明一个比其封闭块寿命更长的闭包
How to declare a closure that lives longer than its enclosing block
我想这个问题一般是关于生命周期的,但是我在闭包方面遇到了困难,特别是因为你不能写出它们的类型。
这个例子有点做作 - 我刚开始学习 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
获得闭包的所有权),此代码将起作用,但由于闭包未调整大小,我必须将其作为参考传递。
是吗?我怎样才能使这段代码工作?
借用不拥有他们指向的东西。你的问题是你借用了一个 temporary ,它在借用后将不复存在,因为你没有将它存储在任何地方。如果有帮助,请考虑借用不借用值,它们借用存储,临时存储只有瞬时存储。
如果您想借用某物以在任何特定时期内持续使用,您必须从将持续至少的存储中借用长。在这种情况下,因为您想将借用存储在 Vec
中,这意味着您借用的任何存储都必须 比 Vec
还长 。因此:
fn main () {
let closure;
let mut list: Vec<&Fn() -> i32> = Vec::new();
{
closure = || 1;
list.push(&closure);
}
}
注意closure
定义在之前是list
。在 Rust 中,值在其作用域的末尾以相反的词法顺序被删除,因此在 list
之后定义的任何变量都必须在它之前被删除,从而导致 list
包含无效指针。
如果要推送多个闭包,则每个闭包都需要一个单独的变量。
为了防止可能的 "my actual problem isn't this simple" 附录 (:P):如果您需要 return list
或以某种方式将其保留到单个函数调用之外,请注意 return list
=30=]无法延长借用。在那种情况下,您需要做的是将 list
更改为 owned 的向量,盒装闭包(即 Vec<Box<Fn() -> i32>>
).
你问的有两件事:
- 为没有可指定类型名称的东西指定类型名称
- 让闭包比定义它的块活得更长。
第一个问题已通过不指定类型名称并让 Rust 的类型推断完成工作来解决。
let mut list: Vec<_> = Vec::new();
第二个问题已解决,方法是不尝试延长闭包的寿命,而是将其设为 "by value" 以便您可以移动它。这强制你的闭包不引用任何东西,但拥有所有捕获的值。
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));
}
}
我想这个问题一般是关于生命周期的,但是我在闭包方面遇到了困难,特别是因为你不能写出它们的类型。
这个例子有点做作 - 我刚开始学习 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
获得闭包的所有权),此代码将起作用,但由于闭包未调整大小,我必须将其作为参考传递。
是吗?我怎样才能使这段代码工作?
借用不拥有他们指向的东西。你的问题是你借用了一个 temporary ,它在借用后将不复存在,因为你没有将它存储在任何地方。如果有帮助,请考虑借用不借用值,它们借用存储,临时存储只有瞬时存储。
如果您想借用某物以在任何特定时期内持续使用,您必须从将持续至少的存储中借用长。在这种情况下,因为您想将借用存储在 Vec
中,这意味着您借用的任何存储都必须 比 Vec
还长 。因此:
fn main () {
let closure;
let mut list: Vec<&Fn() -> i32> = Vec::new();
{
closure = || 1;
list.push(&closure);
}
}
注意closure
定义在之前是list
。在 Rust 中,值在其作用域的末尾以相反的词法顺序被删除,因此在 list
之后定义的任何变量都必须在它之前被删除,从而导致 list
包含无效指针。
如果要推送多个闭包,则每个闭包都需要一个单独的变量。
为了防止可能的 "my actual problem isn't this simple" 附录 (:P):如果您需要 return list
或以某种方式将其保留到单个函数调用之外,请注意 return list
=30=]无法延长借用。在那种情况下,您需要做的是将 list
更改为 owned 的向量,盒装闭包(即 Vec<Box<Fn() -> i32>>
).
你问的有两件事:
- 为没有可指定类型名称的东西指定类型名称
- 让闭包比定义它的块活得更长。
第一个问题已通过不指定类型名称并让 Rust 的类型推断完成工作来解决。
let mut list: Vec<_> = Vec::new();
第二个问题已解决,方法是不尝试延长闭包的寿命,而是将其设为 "by value" 以便您可以移动它。这强制你的闭包不引用任何东西,但拥有所有捕获的值。
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));
}
}