0

I have a piece of code like this:

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

struct A(bool);

impl A {
    fn get_ref(&self) -> &Rc<RefCell<bool>> {
        &Rc::new(RefCell::new(self.0))
    }

    fn copy_ref(&self) -> &Rc<RefCell<bool>> {
        Rc::clone(self.get_ref())
    }
}

fn main() {
    let a = A(true);
    a.copy_ref();
}

and I received warning complaining about the Rc::clone function not getting a reference:

error[E0308]: mismatched types
  --> src/main.rs:12:9
   |
12 |         Rc::clone(self.get_ref())
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found struct `std::rc::Rc`
   |
   = note: expected type `&std::rc::Rc<std::cell::RefCell<bool>>`
              found type `std::rc::Rc<std::cell::RefCell<bool>>`

I have been working on this all night but I cannot get it to work. The method get_ref is already typed as returning &Rc<RefCell<bool>>, but why would the compiler give the error?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Chromium
  • 517
  • 1
  • 6
  • 21

1 Answers1

3

The error is not talking about the argument you put into Arc::clone(), but the whole expression Rc::clone(...) which has a different type (Rc<...>) than the return type of your function (&Rc<...>).

If you were passing a wrong argument to Rc::clone, it would like look this:

  --> src/main.rs:13:19
   |
13 |         Rc::clone(false)
   |                   ^^^^^ expected reference, found bool
   |
   = note: expected type `&std::rc::Rc<_>`
              found type `bool`

So the naive way to fix the type error is to write &Rc::clone(...) instead. Then the last expression of your function has the same type as your function's declared return type. But as you will notice, you will get other errors afterwards.

Let's take a step back to see that your approach is flawed here. For the most important point, please see "Is there any way to return a reference to a variable created in a function?". Spoiler: you really don't want to. So constructs like your get_ref() just don't make sense, as you return a reference to a variable you create inside your function (a variable of type Rc).

In your case the direct solution is probably pretty simple: just remove the reference. Rc<T> is already a pointer/reference type, so there is no need (in general) to have a reference to it.

However, since you are using Rc, you are probably interested in reference counting. So in that case, you probably shouldn't create a new Rc every time the function is called. Otherwise you could end up with a bunch of Rcs with reference count 1, which is not really the point. So instead, your type A should already store an Rc<RefCell<bool>>.

But all I'm doing here is guessing what you actually want to do which is not clear from your question. Maybe you can ask a different question, or add the information to this question, or explain this in the comments.

Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
  • Ok, I know that my code example is not a good one in terms of good rust practices. But just ignore that for now. The point I want to ask is that "why `Rc::clone` doesn't accept my argument in terms of type?" – Chromium Apr 28 '18 at 18:37
  • @Chromium I did address that: you just misunderstood the compiler error. `Rc::clone` *does* accept your argument. Try to write `Rc::clone(self.get_ref()); unimplemented!()` as the body of `copy_ref`. Then you'll see. Also: it is not about good practices. In Rust, the compiler will refuse to compile your code (even if you fix your type error), and in languages like C++ you would access garbage memory and trigger undefined behavior. – Lukas Kalbertodt Apr 28 '18 at 18:43