How do you implement deref on a generic type conta

2019-07-25 08:53发布

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?

标签: rust
1条回答
贪生不怕死
2楼-- · 2019-07-25 09:30

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.

查看更多
登录 后发表回答