Rust: невозможно создать структуру, хранящую значения и ссылки на эти значения

Я создал структуру, в которой хранятся значения и ссылки на них, а также создал метод для добавления значений и заданных времен жизни. Пример кода:

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);
}

Затем я получил ошибку компилятора:

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) {                                                               
                             ^^^         

Я могу исправить эту ошибку и установить для self времени жизни 'a, что касается структуры. Но в этом случае self не будет удален даже после завершения метода. И затем, когда я пытаюсь вызвать метод дважды, я получаю следующую ошибку:

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

Но как разрешить это противоречие?

А может есть в Rust более правильный способ хранения данных в структуре с разрешением доступа к ней не только через владельца?


person arcanius    schedule 03.01.2019    source источник
comment
Технически возможно создать самозаимствующуюся структуру с временем жизни, но такую ​​структуру нельзя переместить (поскольку ее перемещение приведет к аннулированию внутренней ссылки) и нельзя заимствовать изменяемым образом (поскольку она постоянно заимствована неизменно), так что это не так. часто бывает полезно это сделать. Лучший способ продолжить, вероятно, состоит в том, чтобы сделать links Vec<usize> и сохранить индексы (т.е. вместо того, чтобы возиться с ref_x, просто напишите self.links.push(len - 1)).   -  person trentcl    schedule 03.01.2019
comment
Спасибо, trentcl.   -  person arcanius    schedule 03.01.2019
comment
Это отличный пример того, как Rust спасает ваше здравомыслие. В C++ ваш код скомпилировался бы и взорвался во время выполнения. Проблема? Когда вы используете Vec::push, вектору может не хватить места (полная емкость), и в этом случае он выделяет новый массив (в 2 раза больше) и перемещает все элементы в этот новый массив. К сожалению, это означает, что внезапно все ссылки (указатели) на эти элементы становятся висячими: указывая на освобожденную память. И это Undefined Behavior, и могут возникать всевозможные странные эффекты :x   -  person Matthieu M.    schedule 03.01.2019