0

I am very new to Rust and I must be missing something crucial in borrowing/ownership rules because I can not understand why I'm getting an compile error. I'm working with your usual binary tree definitions:

#[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,
        }
    }
}

and somewhere later do I call the following:

/*
* _t1 & _t2 are other TreeNodes.
* merge_trees() is defined as merge_trees(
*    t1: Option<Rc<RefCell<TreeNode>>>,
*    t2: Option<Rc<RefCell<TreeNode>>>,
* ) -> Option<Rc<RefCell<TreeNode>>>
*/
let mut head = TreeNode::new(_t1.borrow().val);
head.left = merge_trees(_t1.borrow().left, _t2.borrow().left);

I get the following error:

error[E0507]: cannot move out of dereference of `std::cell::Ref<'_, TreeNode>`
   --> src/main.rs:234:29
    |
234 |     head.left = merge_trees(_t1.borrow().left, _t2.borrow().left);
    |                             ^^^^^^^^^^^^^^^^^
    |                             |
    |                             move occurs because value has type `std::option::Option<std::rc::Rc<std::cell::RefCell<TreeNode>>>`, which does not implement the `Copy` trait
    |                             help: consider borrowing the `Option`'s content: `_t1.borrow().left.as_ref()`

I'm confused about the error; I can't really seem to parse the text properly. It seems that a move occurred and that's forbidden, but all I did was dereference my TreeNode struct. I realise that simply appending a .clone() would fix this, but I don't know why dereferencing and passing in another TreeNode would be a problem.

Kiwi breeder
  • 459
  • 4
  • 11
  • 2
    "I don't know why dereferencing and passing in another [node] would be a problem" - your `merge_trees` implementation is *consuming* or *taking ownership of* the values passed to it. That is not allowed via a reference because a reference doesn't *own* the original object. – kmdreko Jul 12 '20 at 23:05
  • 1
    Does this answer your question? [Cannot move out of borrowed content / cannot move out of behind a shared reference](https://stackoverflow.com/questions/28158738/cannot-move-out-of-borrowed-content-cannot-move-out-of-behind-a-shared-referen) – kmdreko Jul 12 '20 at 23:05
  • but I'm not passing in a reference into `merge_trees`, I'm directly passing in `std::option::Option>>` – Kiwi breeder Jul 13 '20 at 02:23
  • Sorry, reference wasn't the right term here, but the concept is the same, `left` is owned by `_t1.borrow()` and can't be transferred to `merge_trees()` without a copy or clone. You can see from the error that it attempted to move the entire `TreeNode` out of the `Ref` (one way it could yield an owned `left`) but it couldn't because *that* tries to take ownership from a reference which isn't allowed. – kmdreko Jul 13 '20 at 02:49
  • I can't easily guess what you intend but... You can take ownership from `_t1` via [`take`](https://doc.rust-lang.org/std/option/enum.Option.html#method.take) leaving `None` in its place. You can [`replace`](https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.replace) the TreeNode in the `RefCell` to get the value out. – kmdreko Jul 13 '20 at 03:02
  • Because of the `Rc` you can't get an owned version of the `RefCell` (because that implements shared ownership) without potentially cloning with [`make_mut`](https://doc.rust-lang.org/std/rc/struct.Rc.html#method.make_mut). You can use the shared ownership of the `Rc` and give it `Some(Rc::clone(...))`. – kmdreko Jul 13 '20 at 03:03

0 Answers0