How to declare a closure that lives longer than its blocking block

I suppose this question is about life time in general, but I am having difficulty closing because you cannot write down their type.

This example is a little contrived - I'm just starting to learn Rust, and this is what I got hung up on.

This program will not compile:

fn main () { let mut list: Vec<&Fn() -> i32> = Vec::new(); { list.push(&|| 1); } } 

Because:

 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); ^~~~~~~~~~~~~~~~~ 

What I get from this error is that the closing lifetime is limited inside the block, but it must live for the whole main body.

I know (or, I think) that passing a closure to push as a reference means that push borrows only closure and that the property will be returned to the block. This code will work if I can just give a push closure (i.e., if push took responsibility for the closure), but since the closure has no size, I have to pass it as a link.

It is right? How can I make this code work?

+6
source share
2 answers

There are two things you ask about:

  • specifying a type name for one that does not have a given type name
  • allowing closure to live longer than the block where it is defined.

The first problem was fixed NOT specifying type-name and allowing to make a conclusion like rust.

 let mut list: Vec<_> = Vec::new(); 

The second problem is fixed if you are not trying to make the closure live longer, but by making it "by value" so that you can move it. This ensures that your closure does not reference anything, but has all the fixed values.

 for i in 0..10 { list.push(move || i); } 

Now this gives us a new problem. If we add another closure to Vec , the types will not match. Therefore, to achieve this, we need to close the close window.

 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)); } } 
+8
source

Beards do not own what they point to. Your problem is that you borrow a temporary one, which will cease to exist immediately after borrowing it, because you do not store it anywhere. If this helps, consider that borrowing does not matter, they take up storage, and temporary only has temporary storage.

If you want borrowing to last something for any given period of time, you must borrow storage facilities that will last at least for a long time. In this case, since you want to keep the loan in Vec , this means that any storage that you borrow must also survive Vec . In this way:

 fn main () { let closure; let mut list: Vec<&Fn() -> i32> = Vec::new(); { closure = || 1; list.push(&closure); } } 

Note that closure is defined before list . In Rust, values ​​are lost in the reverse lexical order at the end of their area, so any variable defined after list will necessarily be dropped before it, which will lead to a list containing invalid pointers.

If you want to press multiple closures, you will need a separate variable for each of them.

To prevent a possible β€œmy actual problem is not simple” adding (: P): f you need to return list or somehow save it outside of one function call, please note that there is no way to extend the loan. In this case, you need to change list to a vector belonging to short circuits (i.e. Vec<Box<Fn() -> i32>> ).

+6
source

Source: https://habr.com/ru/post/988128/


All Articles