Rust Trait对象和Trait的直接实现者的Trait实现

Rust Trait对象和Trait的直接实现者的Trait实现,rust,traits,Rust,Traits,我有一个主要封装向量的结构: struct Group<S> { elements: Vec<S> } 我想为组实现Solid,但我想能够为Solid的相同实现列表和Solid的混合实现列表使用组。基本上我想同时使用Group和Group(Sphere实现Solid) 目前,我正在使用类似以下内容: impl Solid for Group<Box<Solid>> { fn intersect(&self, ray: f3

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

struct Group<S> {
    elements: Vec<S>
}
我想为
实现
Solid
,但我想能够为
Solid
的相同实现列表和
Solid
的混合实现列表使用
。基本上我想同时使用
Group
Group
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
    }
}
impl组实体{
fn相交(&self,光线:f32)->f32{
//做事
}
}
组的impl-Solid{
fn相交(&self,光线:f32)->f32{
//做同样的事情,从上一个impl粘贴代码副本
}
}
这是可行的,但让同一代码逐行重复两次并不是惯用的解决方案。我一定错过了什么明显的东西


在我的例子中,我衡量了两种特质实现之间的显著性能差异,因此始终使用
不是一个很好的选择。

对所有
框实施你的特质,其中
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实心框{
fn相交(&self,光线:f32)->f32{
(**自)。相交(光线)
//有些人喜欢这种不那么模棱两可的形式
//S::相交(自、射线)
}
}
您还将发现,对引用执行同样的操作非常有用:

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)
    }
}
impl-Solid表示和{
fn相交(&self,光线:f32)->f32{
(**自)。相交(光线)
//有些人喜欢这种不那么模棱两可的形式
//S::相交(自、射线)
}
}
总而言之:

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);
}
trait-Solid{
fn相交(&self,光线:f32)->f32;
}
盒子的impl-Solid{
fn相交(&self,光线:f32)->f32{
(**自)。相交(光线)
//S::相交(自、射线)
}
}
用于和的impl实体{
fn相交(&self,光线:f32)->f32{
(**自)。相交(光线)
//S::相交(自、射线)
}
}
结构组(Vec);
组的impl-Solid{
fn相交(&self,_射线:f32)->f32{
42.42
}
}
结构点;
点的impl-Solid{
fn相交(&self,_射线:f32)->f32{
100
}
}
fn main(){
让直接=组(向量![点]);
设Box=Group(vec![Box::new(Point)];
设pt=点;
let reference=组(vec![&pt]);
让混合:组=组(vec[
盒子:新的(直接),
盒子:新的(盒装的),
框::新(点),
框::新(参考),
]);
混合、相交(1.0);
}
大小的
绑定允许
S
在编译时没有已知的大小。重要的是,这允许您传入trait对象,例如
Box
&dyn Solid
,因为类型
Solid
没有已知的大小

另见:


@carllevasser我已经更新了关于
?尺寸的现有句子
;更清楚吗?是的,那么如果
是一个
实体
,那么在一个采用
实体
的函数中使用它,我们将有两个“重定向”,这会对性能产生影响吗?此外,什么时候实现它以供参考有用?@Carllevasser这对性能有影响吗?这取决于很多因素(调用频率、编译器优化、单组化等)。唯一的答案是确定自己的个人资料。什么时候为引用实现它有用-只要您有一个trait对象引用而不是一个装箱的trait对象()。。。我不认为我完全理解这个问题。为什么“(**self.intersect(ray)”部分能够编译?我假设“**self”是“?”大小的,它可能不一定能够在堆栈上生存。@GarlicXu但它不需要在堆栈上生存。进行方法调用时,编译器将自动插入引用:
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);
}