0

I'm trying to teach myself Rust by writing a compiler for COOL.

I have a HashMap that stores multiple nodes by name. I also want each node to refer to its parent node if it has one. This way I am able both to find a node by name or navigate the tree from child to parent in constant time.

In this example, I want the node named B to reference A

#![allow(unused_variables)]
#![allow(dead_code)]

use std::collections::HashMap;

struct Node {
    name: String,
    parent_name: Option<String>,
    parent: Option<&'static Node>, // I'm not sure this is the correct lifetime
}

fn main() {
    let mut hm: HashMap<String, Node> = HashMap::new();

    hm.insert(
        "A".to_string(),
        Node {
            name: "A".to_string(),
            parent_name: None,
            parent: None,
        },
    );

    hm.insert(
        "B".to_string(),
        Node {
            name: "B".to_string(),
            parent_name: Some("A".to_string()),
            parent: None,
        },
    );

    // ---------------
    // This is where things go awry.

    let a: &Node = hm.get(&"A".to_string()).unwrap();
    let b: &mut Node = hm.get_mut(&"B".to_string()).unwrap();
    
    b.parent = Some(a);
}

No matter how I change the code I get a error based on multiple references and/or lifetime issues. Is there a way to do this in Rust?

1
  • 2
    You can't use a reference. You need some form of dynamic lifetime checking like an Rc. Or just store the parent name and look the value up in the hash map when needed. Commented Sep 26, 2020 at 22:36

1 Answer 1

1

You can use Rc to let the parent node own by both HashMap and child node, and use RefCell to allow you to mutate the data of immutable reference so that you don't have to borrow hm as mutable and immutable at the same time.

#![allow(unused_variables)]
#![allow(dead_code)]

use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;

struct Node {
    name: String,
    parent_name: Option<String>,
    parent: Option<Rc<RefCell<Node>>>, // use Rc to enable multiple ownership
}

fn main() {
    let mut hm: HashMap<String, Rc<RefCell<Node>>> = HashMap::new();

    hm.insert(
        "A".to_string(),
        Rc::new(RefCell::new(Node {
            name: "A".to_string(),
            parent_name: None,
            parent: None,
        })),
    );

    hm.insert(
        "B".to_string(),
        Rc::new(RefCell::new(Node {
            name: "B".to_string(),
            parent_name: Some("A".to_string()),
            parent: None,
        })),
    );



    let a: &Rc<RefCell<Node>> = hm.get(&"A".to_string()).unwrap();
    let b: &Rc<RefCell<Node>> = hm.get(&"B".to_string()).unwrap();  
    // Can't borrow hm as mutable and immutable at the same time
    // use RefCell to mutate data even when there are immutable references to that data
    
    b.borrow_mut().parent = Some(Rc::clone(a));
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.