1

I'm struggling with the implementation of tree structure in Rust. Particularly, getting and modifying the node's value. What is idiomatic way to work with the value?

Note: the implementation is given and cannot be changed.

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

// Definition for a binary tree node.
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
  pub val: i32,
  pub left: Option<Rc<RefCell<TreeNode>>>,
  pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
  #[inline]
  pub fn new(val: i32) -> Self {
    TreeNode {
      val,
      left: None,
      right: None
    }
  }
}

fn main() {
    let mut root = Some(Rc::new(RefCell::new(TreeNode::new(1))));
    println!("{:?}", root.unwrap().borrow().val); // cannot infer type for type parameter `Borrowed`
    root.unwrap().get_mut().val = 2; // cannot borrow data in an `Rc` as mutable
}
pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
Evgeni Nabokov
  • 2,421
  • 2
  • 32
  • 36
  • 2
    You have two independent problems. The first one is described [here](https://stackoverflow.com/q/25297447/1233251): `root` is moved after calling `unwrap()`. The second one is because you are expected to use `borrow_mut()` instead of `get_mut()`. The latter uses typical inherent mutability instead of interior mutability. – E_net4 May 07 '20 at 18:44
  • Why do you wrap the root in RefCell, Rc and Option? Just `let mut root = TreeNode::new(1)`, then populate branches – Alexey S. Larionov May 07 '20 at 18:44
  • 2
    `Rc>` implies the nodes can be shared by multiple parents. Is that the case? I'd expect nodes in a tree to own their children, in a `Box` say. – John Kugelman May 07 '20 at 18:59
  • Why it is Rc> is out of the scope of the question. The implementation has been given, and I can't change a single byte of it. – Evgeni Nabokov May 07 '20 at 19:04
  • @AlexLarionov because it is in the function signature. I get Option>>, not TreeNode. – Evgeni Nabokov May 07 '20 at 19:51

2 Answers2

1
let root = Some(Rc::new(RefCell::new(TreeNode::new(1))));
let mut v = RefCell::borrow(root.as_ref().unwrap()).val) // Too verbose, but I do not know a brief way.
println!("{}", v); // 1
root.as_ref().unwrap().borrow_mut().val += 1;
v = RefCell::borrow(root.as_ref().unwrap()).val)
println!("{}", v); // 2

Evgeni Nabokov
  • 2,421
  • 2
  • 32
  • 36
1

You can safely unwrap the value if you know it's Some(T). The Rc<T> should work like a transparent container that derefs on method calls, so you can generally treat an Rc<T> as a T, or specifically a RefCell<T> in your case, then you can interact with the value inside the RefCell using the borrow and borrow_mut methods. Example:

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

// Definition for a binary tree node.
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
  pub val: i32,
  pub left: Option<Rc<RefCell<TreeNode>>>,
  pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
  #[inline]
  pub fn new(val: i32) -> Self {
    TreeNode {
      val,
      left: None,
      right: None
    }
  }
}


fn main() {
    let mut root = Some(Rc::new(RefCell::new(TreeNode::new(1))));
    let mut root = root.unwrap();
    println!("{:?}", root.borrow().val); // read access
    root.borrow_mut().val = 2; // write access
}

playground

See also Unwrap and access T from an Option<Rc<RefCell<T>>>

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98