Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"expected struct `std::rc::Rc`, found reference" - how to convert?

Tags:

rust

I tried to get a reference-counted Rc<Foo> from a hash map and put it into a different container (Vec<Foo>).

Thought this would work (by incrementing the reference count), but instead I got an "expected struct std::rc::Rc, found reference" error.

How do I convert an &Rc<Foo> to a Rc<Foo>?


More info:

struct Foo();
let mut foo : HashMap<usize, Rc<Foo>> = HashMap::new();
let mut bar : Vec<Rc<Foo>> = Vec::new();
foo.insert(0, Rc::new(Foo()));
if let Some(x) = foo.get(&0) {
    bar.push(x); // expected struct `std::rc::Rc`, found reference
                 // note: expected type `std::rc::Rc<Foo>`
                 //          found type `&std::rc::Rc<Foo>`  rustc(E0308)
}

I get that the hash map returns a reference to the value it owns. But dereferencing it doesn't work: both if let Some(&x) and bar.push(*x); result in a "cannot move out of borrowed content".

Curiously, adding a type annotation changes the error to "cannot move out of an Rc":

    let x : &Rc<Foo> = x;
    bar.push(*x); // cannot move out of an `Rc`  rustc(E0507)

I need to store a reference to the same object, and not to a copy, so I avoided the .clone() "escape hatch".

like image 976
Nickolay Avatar asked Mar 10 '19 01:03

Nickolay


1 Answers

To convert an &Rc<Foo> -> Rc<Foo>, use Rc::clone(), which gives you an Rc object of your own, increasing the reference count under the hood:

let ref_to_rc: &Rc<Foo> = &Rc::new(Foo());
let new_rc: Rc<Foo> = Rc::clone(ref_to_rc);

rc.clone() is equivalent to Rc::clone(&rc), but idiomatic Rust uses the latter to make it clear that the code only increases the refcount, not performing a deep copy of the data like some other implementations of .clone() do. (Though in some scenarios involving traits you might need to revert to ref_to_rc.clone().)

The errors above were about Rust refusing to do the copy implicitly. Why is std::rc::Rc<> not Copy? has an explanation of why it behaves like that.

like image 70
Nickolay Avatar answered Sep 19 '22 12:09

Nickolay