Why doesn't my structure live long enough?

In Rust, I get the following error:

<anon>:14:9: 14:17 error: `mystruct` does not live long enough <anon>:14 mystruct.update(); ^~~~~~~~ <anon>:10:5: 17:6 note: reference must be valid for the lifetime 'a as defined on the block at 10:4... <anon>:10 { <anon>:11 let initial = vec![Box::new(1), Box::new(2)]; <anon>:12 let mystruct = MyStruct { v : initial, p : &arg }; <anon>:13 <anon>:14 mystruct.update(); <anon>:15 ... <anon>:12:59: 17:6 note: ...but borrowed value is only valid for the block suffix following statement 1 at 12:58 <anon>:12 let mystruct = MyStruct { v : initial, p : &arg }; <anon>:13 <anon>:14 mystruct.update(); <anon>:15 <anon>:16 mystruct <anon>:17 } error: aborting due to previous error 

for the following code:

 struct MyStruct<'a> { v : Vec<Box<i32>>, p : &'a i32 } impl<'a> MyStruct<'a> { fn new(arg : &'a i32) -> MyStruct<'a> { let initial = vec![Box::new(1), Box::new(2)]; let mystruct = MyStruct { v : initial, p : &arg }; mystruct.update(); mystruct } fn update(&'a mut self) { self.p = &self.v.last().unwrap(); } } fn main() { let x = 5; let mut obj = MyStruct::new(&x); } 

(Playground)

I do not understand why mystruct does not live enough. If I comment on the string mystruct.update() , it works fine. What else if I comment on the body of update , the code still doesn't work. Why does calling an empty function that borrows a mutable self change things?

I do not understand what link the error refers to. Can someone explain this?

+5
source share
1 answer

This is evidenced by this error, which is implicitly created when update() called. Since update() accepts &'a mut self , this means that it accepts a value of type &'a mut MyStruct<'a> . This means that in theory you should call update() like this:

 (&mut mystruct).update(); 

It would be very inconvenient to write this everywhere, and therefore Rust can automatically insert the necessary & s, &mut and * to call the method. This is called "autoreference", and the only place this happens is to call the method / access the field.

The problem is the definition of the update() method:

 impl<'a> MyStruct<'a> { ... fn update(&'a mut self) { ... } ... } 

Here, you request that update() get the value that it is called through the link with the lifetime of 'a , where 'a is the lifetime of the link stored in the structure.

However, when you have a structural value that you call this method to, there should already be a link to the i32 that you saved in this structure. Consequently, the lifetime of the structural value is strictly less than the lifetime determined by the lifetime parameter, so constructing &'a mut MyStruct<'a> with local variables (as in your case) is simply impossible.

The solution is to use &mut self instead of &'a mut self :

 fn update(&mut self) { ... } // essentially equivalent to fn update<'b>(&'b mut self) where 'a: 'b { ... } // `'b` is a fresh local lifetime parameter 

Thus, the lifetime of the structure in this method call is not tied to the link; this structure contains and may be less.

Below is a more detailed explanation.

Your very definition is not bullshit. For instance:

 struct IntRefWrapper<'a> { value: &'a i32 } static X: i32 = 12345; static Y: IntRefWrapper<'static> = IntRefWrapper { value: &X }; impl<'a> IntRefWrapper<'a> { fn update(&'a self) { ... } } Y.update(); 

Here, the update() call will not cause compilation errors, because both lifetimes (from Y and X , referenced in Y ): 'static .

Consider your comparison example:

 impl<'a> MyStruct<'a> { fn new(arg : &'a i32) -> MyStruct<'a> { let initial = vec![Box::new(1), Box::new(2)]; let mystruct = MyStruct { v : initial, p : &arg }; mystruct.update(); mystruct } } 

Here we have the parameter lifetime, 'a , which is provided by the calling function. For example, the caller may call this function with a static link:

 static X: i32 = 12345; MyStruct::new(&X); // here &X has static lifetime 

However, when the update() method is called, mystruct 's lifetime is limited to the block in which it is called:

 { let initial = vec![Box::new(1), Box::new(2)]; let mystruct = MyStruct { v : initial, p : &arg }; // + // | mystruct.update(); // | // | mystruct // | } 

Naturally, the borrower's verification tool cannot prove that this lifetime coincides with the lifetime provided by the caller (and for any possible "external" lifetime, this is really impossible for them), so he gives an error.

When an update is defined as follows:

 fn update(&mut self) { ... } // or, equivalently fn update<'b>(&'b mut self) where 'a: 'b { ... } 

then when you call it, it is no longer required that the value that you call by this method should live exactly as long as 'a - it is enough for it to live for any time that is less than or equal to 'a - and the lifetime within the function perfectly matches these requirements. Thus, you can call such a method by its value, and the compiler will not complain.

In addition (as noted in the comments), the following line is really invalid and there is no way around it:

 self.p = &self.v.last().unwrap(); 

Borrowing verification takes place here because you are trying to save a link with the lifetime of the structure in the structure itself. In general, this cannot be done because he has unpleasant problems. For example, suppose you were really able to save this link in a structure. But now you cannot mutate Vec<Box<i32>> in the structure, because it can destroy the element referenced by previously saved links, which makes the code memory unsafe.

It is not possible to verify such things statically, and therefore it is not allowed at the loan verification level. In fact, this is just a pleasant consequence of the general rules for checking loans.

+8
source

All Articles