我有一个结构,它主要封装一个向量:
struct Group<S> {
elements: Vec<S>
}我还有一个简单的特性,它也是为其他结构实现的:
trait Solid {
fn intersect(&self, ray: f32) -> f32;
}我想为Group实现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>>并不是一个很好的选择。
发布于 2015-10-09 15:17:43
为所有Box<S>实现您的特性,其中S实现您的特性。然后您可以委托给现有的实现:
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)
}
}您还会发现,对引用进行同样的操作也是有用的:
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)
}
}合在一起:
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);
}?Sized绑定允许S在编译时不具有已知大小。重要的是,这允许您传递特征对象(如Box<dyn Solid>或&dyn Solid ),因为Solid类型没有已知的大小。
另请参阅:
https://stackoverflow.com/questions/33041736
复制相似问题