Doug
Doug

Reputation: 35106

How do you implement deref on a generic type containing a trait in rust?

It would be rather convenient to be able to use Deref to generate a &TraitType from a generic container, rather than calling instance.as_ref(). ie:

(*my_container).do_thing();

vs.

my_container.as_ref().do_thing();

To do this I tried to implement Deref on the container type, but I get this error:

<anon>:9:28: 9:29 error: expected a reference to a trait [E0172]
<anon>:9 impl<T> Deref for HasTrait<T + Send> {

From:

use std::ops::Deref;

trait Foo {}

struct HasTrait<T> {
  data:Box<T>
}

impl<T> Deref for HasTrait<T + Send> {
  type Target = T;
  fn deref<'a>(&'a self) -> &'a T {
    return self.as_ref();
  }
}

struct IsFoo;
unsafe impl Send for IsFoo {}
impl Foo for IsFoo {}


fn main() {
  let is_foo = IsFoo;
  let foo:Box<Foo> = box is_foo as Box<Foo>;
  let has_foo = HasTrait { data: foo };
  let foo_ref:&Foo = *has_foo; 
}

I've tried using ?Sized to increase the bounds of T to allow traits, but it didn't seem to help?

What's the right way to do this?

Upvotes: 2

Views: 2208

Answers (1)

Vladimir Matveev
Vladimir Matveev

Reputation: 127711

This works:

use std::ops::Deref;

struct HasTrait<T: ?Sized> {
    data: Box<T>
}

impl<T: ?Sized> HasTrait<T> {
    fn as_ref(&self) -> &T {
        &*self.data
    }
}

impl<T: ?Sized> Deref for HasTrait<T> {
    type Target = T;

    fn deref<'a>(&'a self) -> &'a T {  // '
        self.as_ref()
    }
}

trait Foo {}
struct IsFoo;
impl Foo for IsFoo {}

fn main() {
    let is_foo = IsFoo;
    let foo: Box<Foo> = box is_foo as Box<Foo>;
    let has_foo = HasTrait { data: foo };
    let foo_ref: &Foo = &*has_foo; 
}

Basically, your problem wasn't really connected with sizedness. It's just that HasTrait<T + Send> here:

impl<T> Deref<T> for HasTrait<T + Send>

is meaningless. T can be arbitrary type, and something like u64 + Send does not make sense. Consequently, I'm afraid, you won't be able to constrain HasTrait to contain only traits and only for those types which are Send. There is just no syntax for that, and I'm pretty sure the type system does not support it.

Upvotes: 1

Related Questions