trait 对象和 trait 的直接实现者的 trait 实现 [英] Trait implementation for both a trait object and for direct implementors of the trait

查看:68
本文介绍了trait 对象和 trait 的直接实现者的 trait 实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a struct that mostly encapsulates a vector:

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

我还有一个简单的 trait,它也为其他结构体实现了:

I also have a simple trait which is also implemented for other structs:

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

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

I want to implement Solid for Group, but I want to be able to use Group both for lists of the same implementation of Solid and for lists of mixed implementations of Solid. Basically I want to use both Group<Box<Solid>> and Group<Sphere> (Sphere implements Solid).

目前我正在使用这样的东西:

Currently I am using something like this:

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

这行得通,但是将相同的代码逐行放置两次不是惯用的解决方案.我一定遗漏了一些明显的东西?

This works, but having line-for-line the same code twice can't be the idiomatic solution. I must be missing something obvious?

在我的例子中,我测量了两种 trait 实现之间的显着性能差异,因此总是使用 Group> 并不是一个好的选择.

In my case I measure a notable performance difference between both trait implementations, so always using Group<Box<Solid>> isn't a great option.

推荐答案

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

Implement your trait for all Box<S> where S implements your trait. Then you can delegate to the existing implementation:

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

您还会发现对引用执行相同操作也很有用:

You'll also find that it can be useful to do the same for references:

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 对象,例如 Box&dyn Solid 作为类型 Solid 没有已知大小.

The ?Sized bound allows the S to not have a size known at compile time. Importantly, this allows you to pass in trait objects such as Box<dyn Solid> or &dyn Solid as the type Solid does not have a known size.

另见:

这篇关于trait 对象和 trait 的直接实现者的 trait 实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆