How to implement Deref when Target is a Ref<'a, T>?

I have an structure in a Rc<RefCell<Vec>> for some type that I wanted to implement Deref for so I could transparently access the Vec. In the below example, the type is called Foo and I removed the Rc for clarity. The compiler is complaining about the lifetime parameter not being constrained.

I wanted to understand this error a little better, and see if there is a work around.

Is this a limitation of the borrow checker algorithm, or is this subtly unsafe in a way that I'm not seeing?

use std::cell::{ RefCell, Ref };
use std::ops::Deref;

struct Foo {
    data: RefCell<Vec<u8>>
}

impl<'a> Deref for Foo {
    type Target = Ref<'a, Vec<u8>>;
    
    fn deref(&'a self) -> &Self::Target {
        &self.data.borrow()
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
 --> src/lib.rs:8:6
  |
8 | impl<'a> Deref for Foo {
  |      ^^ unconstrained lifetime parameter

error: aborting due to previous error

For more information about this error, try `rustc --explain E0207`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

You can't implement Deref for things containing a RefCell. One thing I sometimes see is to define a struct with a Ref<Vec<u8>> field and implement Deref on that.

1 Like

Could you explain what that would look like a little bit more? If I were to put the Ref<Vec<u8>> as a field in a struct, the struct would still need the lifetime parameter for the Ref. See the docs, Ref's type signature is Ref<'b, T>.

I just omitted it. It would look like this:

struct Foo<'a> {
    data: Ref<'a, Vec<u8>>
}

impl<'a> Deref for Foo<'a> {
    type Target = [u8];
    
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

playground

Ah, I understand now, but that isn't really a solution for my particular use case, since I want to implement Deref on a struct that contains a RefCell, not on a struct that contains a Ref.

Thanks though!

EDIT: I'm confused where you would use that example, since impl<'_, T> Deref for Ref<'_, T> is already implemented, see the "Trait Implementations" on the docs for Ref. The example just appears redundant to me.

I guess the thing I'm not understanding is why I can't implement Deref for things containing a RefCell

You would use it by making a function on your RefCell-containing struct that hands out a struct wrapping a Ref, you'd probably call it borrow(). And then that handle could implement Deref using the Ref's Deref impl.

Because of the signature of Deref. It must return a reference, not a Ref. And the only way to obtain a reference to the wrapped value of a RefCell is to go through the Ref which is the return value of RefCell:borrow(), i.e. a temporary, so you can't even return a reference to it or into it. (Well, unless you store it along with the original struct, but then that becomes perma-borrowed, rendering it essentially useless.)

Thanks for the explanation, I feel silly for not seeing that earlier!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.