我有一个主要封装矢量的结构:
struct Group<S> {
elements: Vec<S>
}
我还有一个简单的特性,也可以用于其他结构:
trait Solid {
fn intersect(&self, ray: f32) -> f32;
}
我想为Solid
实施Group
,但我希望能够将Group
用于Solid
的相同实施的列表以及混合列表Solid
的实现。基本上我想同时使用Group<Box<Solid>>
和Group<Sphere>
(Sphere
实现Solid
)。
目前我使用的是这样的东西:
impl Solid for Group<Box<Solid>> {
fn intersect(&self, ray: f32) -> f32 {
//do stuff
}
}
impl<S: Solid> Solid for Group<S> {
fn intersect(&self, ray: f32) -> f32 {
//do the same stuff, code copy-pasted from previous impl
}
}
这样可行,但两次使用相同代码的行不能成为惯用解决方案。我一定错过了一些明显的东西吗?
就我而言,我衡量两种特质实施之间的显着性能差异,因此始终使用Group<Box<Solid>>
并不是一个很好的选择。
答案 0 :(得分:4)
为所有Box<S>
实施您的特征S
实现您的特质。然后,您只需委托现有的实现:
impl<S: Solid + ?Sized> Solid for Box<S> {
fn intersect(&self, ray: f32) -> f32 {
(**self).intersect(ray)
}
}
您还会发现对引用执行相同操作非常有用:
impl<'a, S: Solid + ?Sized> Solid for &'a S {
fn intersect(&self, ray: f32) -> f32 {
(**self).intersect(ray)
}
}
所有在一起:
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)
}
}
impl<'a, S: Solid + ?Sized> Solid for &'a S {
fn intersect(&self, ray: f32) -> f32 {
(**self).intersect(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<Solid>> = Group(vec![
Box::new(direct),
Box::new(boxed),
Box::new(Point),
Box::new(reference),
]);
mixed.intersect(1.0);
}
?Sized
绑定允许S
在编译时没有已知的大小。重要的是,这允许您传递特征对象,例如Box<Solid>
或&Solid
,因为类型Solid
没有已知大小。