Creating a simple tree-like structure where parent/child nodes is fairly easy in most languages. The Typescript example below does the following:
creates a parent
adds a child to the parent
grabs the newly created child
adds a grandchild to the child
prints out the parent including its decendants
// typescript example:
class Node {
id:string;
children:Array<Node> ;
constructor(id:string) {
this.id = id;
this.children = [];
}
public addChild(id:string):Node {
let child = new Node(id);
this.children.push(child);
return child;
}
}
const parent:Node = new Node("parent");
const child:Node = parent.addChild("child");
const grandchild:Node = child.addChild("grandchild");
console.log(JSON.stringify(parent));
What would be the Rust idiomatic way of doing the same thing?
(Below is a simple attempt that in the end creates the same parent>child>grandchild relation, but is very limitied in that the add_child function doesn't return the child created . so I must keep refering to parent all the time... I'm sure it all comes down to my limited knowledge of Rust's borrowing handling!)
fn main() {
let mut parent = Node::new("Parent".to_string());
parent.add_child("Child".to_string());
// Can I somehow get hold of the child as a mutable variable here?
// the following is very limited and ugly...
parent.children[0].add_child("Grandchild".to_string());
println!("{:?}", parent);
}
#[derive(Debug)]
struct Node {
id:String,
children:Vec<Node>,
}
impl Node {
fn new(id:String)->Node {
Node {id, children:vec![]}
}
fn add_child(&mut self, id:String) {
let child = Node::new(id);
self.children.push(child);
}
}
Thanks a lot, 2e71828! Didn't know of the .last_mut() method.
That works. However, the add_child method isn't returning the child directly - it is returned "via" children.last_mut().unwrap().
What if the children field was something else than a simple Vec pushed to, so that I couldn't rely on last_mut()?
Alternatively, you can build the tree bottom-up instead of top-down
Yes, that may be a better solution in many cases. But this example was created just for hoping to better understand how to deal with the ownership model. Thanks!
If anyone's interested, here's the original example modified with @2e71828's suggested solution: