Какие времена жизни я использую для создания структур Rust, которые циклически ссылаются друг на друга?

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

struct Parent<'me> {
    children: Vec<Child<'me>>,
}

struct Child<'me> {
    parent: &'me Parent<'me>,
    i: i32,
}

fn main() {
    let mut p = Parent { children: vec![] };
    let c1 = Child { parent: &p, i: 1 };
    p.children.push(c1);
}

Я пытался успокоить компилятор временем жизни, не понимая полностью, что делаю.

Вот сообщение об ошибке, в котором я застрял:

error[E0502]: cannot borrow `p.children` as mutable because `p` is also borrowed as immutable
  --> src/main.rs:13:5
   |
12 |     let c1 = Child { parent: &p, i: 1 };
   |                               - immutable borrow occurs here
13 |     p.children.push(c1);
   |     ^^^^^^^^^^ mutable borrow occurs here
14 | }
   | - immutable borrow ends here

В этом есть смысл, но я не совсем уверен, что делать дальше.


person Grumdrig    schedule 20.12.2013    source источник


Ответы (1)


Невозможно создать циклические структуры с заимствованными указателями.

В настоящее время не существует хорошего способа создания циклических структур данных; единственные реальные решения:

  1. Используйте подсчет ссылок с Rc<T> с циклической структурой с Rc::new и _ 3_. Прочтите rc документацию модуля и будьте осторожны, чтобы не создавать циклические структуры, использующие сильные ссылки, так как это вызовет утечку памяти.
  2. Используйте необработанные / небезопасные указатели (*T).
person Chris Morgan    schedule 20.12.2013
comment
Спасибо; очень полезно знать. Думаю, я посмотрю, смогу ли я реорганизовать умные элементы в Child до Parent и избавиться от необходимости в родительском указателе. - person Grumdrig; 20.12.2013
comment
На самом деле, эта идея - маленький кошмар, и *T кажется именно тем, что я хочу. Но я не могу использовать его для доступа к членам Parent. Когда я пытаюсь использовать c1.parent.i (при условии, что у Родителя есть поле i:int, не показанное в моем примере), я получаю error: attempted access of field 'i' on type '*Parent', but no field with that name was found. Я не могу найти много информации об этих зверях. - person Grumdrig; 20.12.2013
comment
Неважно. Rust не подслащивает небезопасные указатели автоматически, поэтому (*c1.parent).i работает (в блоке unsafe). - person Grumdrig; 20.12.2013
comment
Если дочерний объект хранит std::rc::Weak вместо Rc, он должен нормально работать без new_unchecked, поскольку не будет (сильных) циклических ссылок. - person Pavel Strakhov; 05.09.2016
comment
Этот ответ еще действителен? - person Ekrem Dinçel; 31.12.2020
comment
@ EkremDinçel: да, и вряд ли когда-нибудь это изменится. - person Chris Morgan; 03.01.2021