rust - 特征对象和特征的直接实现者的特征实现

标签 rust traits

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

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
    }
}

这行得通,但是两次逐行使用相同的代码不能成为惯用的解决方案。我一定遗漏了一些明显的东西吗?

在我的例子中,我测量了两个 trait 实现之间的显着性能差异,所以总是使用 Group<Box<Solid>>不是一个很好的选择。

最佳答案

为所有 Box<S> 实现你的特征在哪里 S实现你的特质。然后你可以委托(delegate)给现有的实现:

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绑定(bind)允许S在编译时没有已知的大小。重要的是,这允许您传入 trait 对象,例如 Box<dyn Solid>&dyn Solid作为类型Solid没有已知的大小。
也可以看看:
  • What does the question mark mean in a type parameter bound?
  • What makes something a "trait object"?
  • What does "dyn" mean in a type?
  • 关于rust - 特征对象和特征的直接实现者的特征实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63257600/

    相关文章:

    php - 如何使用 php 使用特征内的对象初始化属性?

    rust - 借来的可变类型

    rust - 如何为枚举实现 PartialEq?

    string - 如何在不乱码的情况下存储与格式宏一起使用的大字符串文字?

    rust - 创建一个实现特定 Fn 接口(interface)的结构

    rust - 为实现特定类型的 trait 的泛型类型实现 trait

    scala - 什么是密封特质?

    rust - 作为函数指针类型 : what is the correct type definition? 的异步函数

    rust - 为什么 Diesel 结构中的可选字段未实现特征

    scope - 特征中的项目只能在特征已实现且在范围内时使用