What is the right way to handle parent /child relation?

I am a rookie in rust. I have a parent / child relation (e.g. in a database) and want to build a list of business objects, where each contains a parent and its children in a vector. Therefore I want to iterate a vector of all parents and filter another vector of all children. As the business object is what I want to use later in code, it should get the onwership of parent and its children. But how to do that?
I started with the following:

struct Parent{
    id: i64,
}

struct Child {
    id: i64,
    parent_id: i64,
    xyz: String
}

struct BusinessObject{
    parent: Parent,
    children: Vec<Child>,
}

fn main() {
    let parents = vec![Parent{id:1}, Parent{id:2}];
    let all_children = vec![
        Child{id:11, parent_id: 1, xyz: "aaa".to_owned()},
        Child{id:12, parent_id: 2, xyz: "aab".to_owned()},
        Child{id:13, parent_id: 2, xyz: "aac".to_owned()},
        Child{id:14, parent_id: 1, xyz: "aad".to_owned()},
        Child{id:15, parent_id: 2, xyz: "aae".to_owned()},
    ];

    // busis shall get onwership 
    let mut busis: Vec<BusinessObject> = vec![];

    for parent in parents.into_iter() {
        let children = all_children.into_iter().filter(|c| c.parent_id == parent.id).collect();
        busis.push(BusinessObject{parent, children});
    }
}

(Playground)
But here the compiler tells me that I will loose ownership of all_children while iterating.
I found an other way to handle it using a hashmap for children vector (Playground workaround), but I wounder if that is the way I should handle this?

The lifetime system in Rust generally depends on ownership being acyclic, so you need to watch out when having both parent and children access each other. In this case you are ok, as neither the parent nor the child has any sort of reference to each other, but I'm just warning you.

As for the problem you're dealing with, the issue is that into_iter takes ownership of the vector you use it on, so you need a different technique to create the business objects from the given data. One approach is to split the loop into two like this:

for parent in parents {
    busis.push(BusinessObject {
        parent,
        children: Vec::new(),
    });
}
for child in all_children {
    // This lookup is inefficient, and could be improved by a hashmap.
    let busis = busis.iter_mut().find(|b| b.parent.id == child.parent_id).unwrap();
    busis.children.push(child);
}

playground

@alice: That sounds all plausible to me.
Thank you for your work / your time!!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.