-1

The program below compiles and runs if Rc is replaced with Box. Why doesn't it compile when using reference counting? This is a question about the difference between Rc<T> and Box<T>.

use std::rc::Rc;

#[derive(Debug, Clone)]
pub enum ILst {
    Nil,
    Cons(i32, Rc<ILst>),
}

impl ILst {
    pub fn new() -> Self {
        ILst::Nil
    }

    pub fn cons(self, item: i32) -> Self {
        ILst::Cons(item, Rc::new(self)) 
    }

    pub fn car(&self) -> Option<i32> {
        match *self {
            ILst::Cons(u, ref _v) => Some(u),
            ILst::Nil => None,
        }
    }

    pub fn cdr(&self) -> Self {
        match *self {
            ILst::Cons(_u, ref v) => *v.clone(),
            ILst::Nil => ILst::Nil,
        }
    }
}

fn main() {
    let list = ILst::new().cons(17).cons(29);
    let rest = list.cdr();
    println!("list  = {:?}", rest);
}
error[E0507]: cannot move out of borrowed content
  --> src/main.rs:27:38
   |
27 |             ILst::Cons(_u, ref v) => *v.clone(),
   |                                      ^^^^^^^^^^ cannot move out of borrowed content
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Anthony Maida
  • 591
  • 3
  • 8
  • I believe your question is answered by the answers of [How do I get an owned value out of a `Box`?](https://stackoverflow.com/q/42264041/155423): *"because Box is special"*. If you disagree, please [edit] your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Sep 24 '18 at 19:39
  • *the difference between `Rc` and `Box`* — yes, [`Box` is special](https://stackoverflow.com/q/42264041/155423). – Shepmaster Sep 24 '18 at 20:03

1 Answers1

1

The solution seems to be to replace

*v.clone()

with

Rc::deref(v).clone()

and then add the line

use::ops::Deref;

to the beginning of the program.

Anthony Maida
  • 591
  • 3
  • 8
  • Why doesn't `*v` work? Isn't prefix `*` the syntax for `std::ops::Deref`? Is `*` the deref operation of some other type? – starblue Sep 25 '18 at 10:17
  • Regarding above comment, yes, that would make sense to me. But for some reason it's not so. I, too, would like an explanation. – Anthony Maida Sep 27 '18 at 01:18
  • `Deref` behaves differently (moving out of the deref) when it's invoked as `*` - see [Why is the return type of Deref::deref itself a reference?](https://stackoverflow.com/q/31624743/9118790). As an alternative, you can usually use `&*` to dereference and reborrow, so the line could also be replaced with `(&**v).clone()` (using an extra `*` undo the `ref v`). (Sometimes rustc will suggest `&*`, but it might not recognize the double-deref in this case.) – wartmanm Sep 27 '18 at 15:38
  • Yes, I verified the above works. Thank you for the explanation. – Anthony Maida Sep 28 '18 at 17:18