首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >特性对象和该特性的直接实现者的特性实现

特性对象和该特性的直接实现者的特性实现
EN

Stack Overflow用户
提问于 2015-10-09 15:11:36
回答 1查看 2.5K关注 0票数 15

我有一个结构,它主要封装一个向量:

代码语言:javascript
复制
struct Group<S> {
    elements: Vec<S>
}

我还有一个简单的特性,它也是为其他结构实现的:

代码语言:javascript
复制
trait Solid {
    fn intersect(&self, ray: f32) -> f32;
}

我想为Group实现Group,但我希望能够将Group用于相同实现的Solid列表和Solid的混合实现列表。基本上,我想同时使用Group<Box<Solid>>Group<Sphere> (Sphere实现Solid)。

目前我使用的是这样的东西:

代码语言:javascript
复制
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>>并不是一个很好的选择。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-10-09 15:17:43

为所有Box<S>实现您的特性,其中S实现您的特性。然后您可以委托给现有的实现:

代码语言:javascript
复制
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)
    }
}

您还会发现,对引用进行同样的操作也是有用的:

代码语言:javascript
复制
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)
    }
}

合在一起:

代码语言:javascript
复制
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类型没有已知的大小。

另请参阅:

票数 20
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33041736

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档