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

struct Group<S> {
    elements: Vec<S>
}

我还有一个简单的特点,也适用于其他 struct :

trait Solid {
    fn intersect(&self, ray: f32) -> f32;
}

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

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

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>>并不是一个好的 Select .

推荐答案

实现你的trait Box<S>人,其中S人实现了你的trait .然后可以委托给现有的实现:

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在编译时没有已知的大小.重要的是,这允许您传入trait objects,例如Box<dyn Solid>&dyn Solid,因为Solid型没有已知的尺寸.

另见:

Rust相关问答推荐

as操作符如何将enum转换为int?

如何从polars DataFrame中获取一个列作为Option String?<>

使用 struct 外部的属性来改变 struct 的原始方式

为什么reqwest以文本形式下载二进制文件?

如何删除Mac Tauri上的停靠图标?

一种随机局部搜索算法的基准(分数)

在rust sqlx中使用ilike和push bind

我应该将哪些文件放入我的GitHub存储库

我无法理解Rust范围的定义(Rust Programming Language,第二版克拉布尼克和尼科尔斯)

获取与父字符串相关的&;str的原始片段

如何在Rust中基于字符串 Select struct ?

这是什么:`impl Trait for T {}`?

在什么情况下 `..._or()` 比 `..._or_else(|| {})` 更好,为什么?

我可以解构self 参数吗?

`use` 和 `crate` 关键字在 Rust 项目中效果不佳

Rust 异步循环函数阻塞了其他future 任务的执行

`tokio::pin` 如何改变变量的类型?

max(ctz(x), ctz(y)) 有更快的算法吗?

打印 `format_args!` 时borrow 时临时值丢失

如何将 u8 切片复制到 u32 切片中?