Trait implementation for both a trait object and for direct implementors of the trait
Solution 1:
Implement your trait for all Box<S>
where S
implements your trait. Then you can delegate to the existing implementation:
impl<S: Solid + ?Sized> Solid for Box<S> {
fn intersect(&self, ray: f32) -> f32 {
(**self).intersect(ray)
// Some people prefer this less-ambiguous form
// S::intersect(self, ray)
}
}
You'll also find that it can be useful to do the same for references:
impl<S: Solid + ?Sized> Solid for &'_ S {
fn intersect(&self, ray: f32) -> f32 {
(**self).intersect(ray)
// Some people prefer this less-ambiguous form
// S::intersect(self, ray)
}
}
All together:
trait Solid {
fn intersect(&self, ray: f32) -> f32;
}
impl<S: Solid + ?Sized> Solid for Box<S> {
fn intersect(&self, ray: f32) -> f32 {
(**self).intersect(ray)
// S::intersect(self, ray)
}
}
impl<S: Solid + ?Sized> Solid for &'_ S {
fn intersect(&self, ray: f32) -> f32 {
(**self).intersect(ray)
// S::intersect(self, ray)
}
}
struct Group<S>(Vec<S>);
impl<S: Solid> Solid for Group<S> {
fn intersect(&self, _ray: f32) -> f32 {
42.42
}
}
struct Point;
impl Solid for Point {
fn intersect(&self, _ray: f32) -> f32 {
100.
}
}
fn main() {
let direct = Group(vec![Point]);
let boxed = Group(vec![Box::new(Point)]);
let pt = Point;
let reference = Group(vec![&pt]);
let mixed: Group<Box<dyn Solid>> = Group(vec![
Box::new(direct),
Box::new(boxed),
Box::new(Point),
Box::new(reference),
]);
mixed.intersect(1.0);
}
The ?Sized
bound allows the S
to not have a size known at compile time. Importantly, this allows you to pass in trait objects such as Box<dyn Solid>
or &dyn Solid
as the type Solid
does not have a known size.
See also:
- What does the question mark mean in a type parameter bound?
- What makes something a "trait object"?
- What does "dyn" mean in a type?