I'd like to implement Deref
and DefrefMut
on a struct that owns a boxed trait, e.g.:
use std::ops::{Deref, DerefMut};
trait Quack {
fn quack(&self);
}
struct QuackWrap {
value: Box<Quack>
}
impl Deref for QuackWrap {
type Target = Box<Quack>;
fn deref<'a>(&'a self) -> &'a Box<Quack> {
&self.value
}
}
impl DerefMut for QuackWrap {
fn deref_mut<'a>(&'a mut self) -> &'a mut Box<Quack> {
&mut self.value
}
}
This fails to compile with the following error:
src/main.rs:14:5: 16:6 error: method `deref` has an incompatible type for trait: expected bound lifetime parameter 'a, found concrete lifetime [E0053]
src/main.rs:14 fn deref<'a>(&'a self) -> &'a Box<Quack> {
src/main.rs:15 &self.value
src/main.rs:16 }
src/main.rs:20:5: 22:6 error: method `deref_mut` has an incompatible type for trait: expected bound lifetime parameter 'a, found concrete lifetime [E0053]
src/main.rs:20 fn deref_mut<'a>(&'a mut self) -> &'a mut Box<Quack> {
src/main.rs:21 &mut self.value
src/main.rs:22 }
If I replace Box<Quack>
with Box<String>
(or a similar type), it works. The problem is that Quack
is a trait. But I'm not sure why that generated the error message it did. Any ideas?
My question is similar to another SO question, but not quite the same. In that question, the struct has a type parameter with the trait as a constraint. Whereas in my question, there is no type parameter.
I don't want to confuse the issues, but there's a good reason that I need Box<Quack>
in my application. I.e. I can't replace Quack
with a type parameter. In case you care, the reason is discussed further in another SO question.
When in doubt, add more lifetime annotations:
use std::ops::{Deref, DerefMut};
trait Quack {
fn quack(&self);
}
struct QuackWrap<'b> {
value: Box<Quack + 'b>
}
impl<'b> Deref for QuackWrap<'b>{
type Target = Box<Quack + 'b>;
fn deref<'a>(&'a self) -> &'a Box<Quack + 'b> {
&self.value
}
}
impl<'b> DerefMut for QuackWrap<'b> {
fn deref_mut<'a>(&'a mut self) -> &'a mut Box<Quack + 'b> {
&mut self.value
}
}
Based on Brian's answer and Shepmaster's explanation, I updated my code as follow. I also simplified the QuackWrap
struct. (That wasn't strictly necessary, but it's arguably better style than what I was doing before.)
use std::ops::{Deref, DerefMut};
trait Quack {
fn quack(&self);
}
struct QuackWrap(Box<Quack>);
impl Deref for QuackWrap {
type Target = Box<Quack + 'static>;
fn deref<'a>(&'a self) -> &'a Box<Quack + 'static> {
let QuackWrap(ref v) = *self;
v
}
}
impl DerefMut for QuackWrap {
fn deref_mut<'a>(&'a mut self) -> &'a mut Box<Quack + 'static> {
let QuackWrap(ref mut v) = *self;
v
}
}
There may be a more concise way to destructure QuackWrap
in the deref
and deref_mut
implementations. Some of those more obscure syntax rules elude me. But for now this is fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With