2

I created a structure that stores values and references to them, and also created a method for adding values and specified lifetimes. Code example:

struct Storage<'a> {
    owner :Vec<i32>,
    links :Vec<&'a i32>
}

impl<'a> Storage<'a> {
    fn new() -> Storage<'a> {
        Storage {owner: vec![], links: vec![]}
    }

    fn add_int(&mut self, x :i32) {
        self.owner.push(x);
        let len = self.owner.len();
        let ref_x = match self.owner.get(len-1) {
            Some(x) => x,
            None => panic!("ERROR")
        };
        self.links.push(ref_x);
        let ref_x = 0;
    }
}

fn main() {
    let mut store = Storage::new();
    store.add_int(1);
    store.add_int(2);
}

Then I got a compiler error:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
let ref_x = match self.owner.get(len-1) {                                                               
                             ^^^         

I can correct this mistake and set for self lifetime 'a, as for the structure. But in this case self will not be deleted even after the completion of the method. And then when I try to call the method twice, I get the following error:

error[E0499]: cannot borrow `store` as mutable more than once at a time

But how can this contradiction be resolved?

And maybe there is a more correct way in Rust of storing data in the structure with allowing access to it not only through the owner?

arcanius
  • 21
  • 1
  • 1
    It's technically possible to create a self-borrowing struct with lifetimes, but such a struct can't be moved (because moving it would invalidate the internal reference) and can't be borrowed mutably (because it's permanently borrowed immutably), so it's not often useful to do so. The best way to proceed is probably to make `links` a `Vec` and store indices (i.e. instead of messing about with `ref_x`, just write `self.links.push(len - 1)`). – trent Jan 03 '19 at 15:05
  • Thanks, trentcl. – arcanius Jan 03 '19 at 15:28
  • 5
    This is an excellent example of Rust saving your sanity. In C++, your code would have compiled, and blown up at run-time. The problem? When you use `Vec::push`, the vector may run out of space (full capacity), in which case it allocates a new array (2x larger), and moves all the elements to that new array. Unfortunately, that means that all of a sudden all the references (pointers) to those elements become *dangling*: pointing to freed memory. And that's Undefined Behavior, and all kinds of strange effects can occur :x – Matthieu M. Jan 03 '19 at 15:31

0 Answers0