Objects in array referencing each other

Is there some way to create an array at runtime with two elements having references to each other?

Basically I have data-structures that might contain loops, hence I can not use RC or similar structures.
Instead I would like to have one object owning the elements and being responsible for cleanup and the other objects referencing each other.

Maybe the following attempt helps clarifty the question - it does manage to create the array with the element [1] referencing element[0] ...
however if I try to access the array (e.g. uncommenting the last println!) it fails, since the array was borrowed mutably and through its own element that borrow is kept (at least that's how I understood the situation).

#[derive(Debug)]
struct Elem<'a> {
    id: String,
    other: Option<&'a Self>,
}
#[derive(Debug)]
struct Owner<'a> {
    elems: [Elem<'a>; 2],
}
impl<'a> Owner<'a> {
    fn new() -> Self {
        Self {
            elems: [
                Elem {
                    id: "Elem0".to_owned(),
                    other: None,
                },
                Elem {
                    id: "Elem1".to_owned(),
                    other: None,
                },
            ],
        }
    }
}

fn main() {
    let mut parent = Owner::new();
    {
        let (elem0a, elem1a) = parent.elems.split_at_mut(1);
        elem1a[0].other = Some (&elem0a[0]);
        println!("elem1a[0] = {:#?}", elem1a[0]);
    }
    //println!("Parent = {:#?}", parent);
}

(Playground)

No, objects in Rust cannot be self-referential. One option is to use Rc and Weak to break cycles.

2 Likes

ok, thanks I will try that.

Tried it, it works. Thanks again:

use std::rc::{Rc, Weak};

#[derive(Debug)]
struct Elem {
    id: String,
    other: Option<Weak<Self>>,
}
#[derive(Debug)]
struct Owner {
    elems: [Rc<Elem>; 2],
}
impl Owner {
    fn new() -> Self {
        Self {
            elems: [
                Rc::new(Elem {
                    id: "Elem0".to_owned(),
                    other: None,
                }),
                Rc::new(Elem {
                    id: "Elem1".to_owned(),
                    other: None,
                }),
            ],
        }
    }
}

fn main() {
    let mut parent = Owner::new();
    {
        let (elem0a, elem1a) = parent.elems.split_at_mut(1);
        Rc::get_mut(&mut elem1a[0]).unwrap().other = Some (Rc::downgrade(&elem0a[0]));
        println!("elem1a[0] = {:#?}", elem1a[0]);
    }
    println!("Parent = {:#?}", parent);
}

(Playground)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.