【问题标题】:Idiomatic way to structure Rust trait构造 Rust 特征的惯用方法
【发布时间】:2019-03-09 01:01:18
【问题描述】:

在“The Ray Tracer Challenge”之后,我一直在用 Rust 编写 Ray Caster,我一直很难找出在 Rust 中实现多态性的正确方法。我的优先事项是该对象可以在多线程程序中使用,这似乎是主要问题。

我有两个案例,但我会专注于一个:形状。有不同种类的形状(坚持使用able 后缀,我最初将我的特征称为Intersectable)。这是一个有效的 trait 对象实现,但它不适用于多线程:

#[derive(Debug)]
pub struct Shape {
    pub parent: Option<Arc<Shape>>,
    pub transform: Matrix4,
    pub material: Material,
    pub intersectable: Box<Intersectable>,
}
pub trait Intersectable: Debug + IntersectableClone {
    fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>;
}

pub trait IntersectableClone {
    fn clone_box(&self) -> Box<Intersectable>;
}

impl<T> IntersectableClone for T
where
    T: 'static + Intersectable + Clone,
{
    fn clone_box(&self) -> Box<Intersectable> {
        Box::new(self.clone())
    }
}

impl Clone for Box<Intersectable> {
    fn clone(&self) -> Box<Intersectable> {
        self.clone_box()
    }
}

#[derive(Clone, Debug)]
pub struct Sphere {}

impl Intersectable for Sphere {
    fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection> {
        ...sphere specific code
    }
}

#[derive(Clone, Debug)]
pub struct Plane {}

impl Intersectable for Plane {
    fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection> {
        ...plane specific code
    }
}

作为一个纯结构,没有官方多态,我写了一种静态调度,看起来像这样:

#[derive(Debug, Clone)]
pub enum IntersectableType {
    Sphere,
    Plane,
}

#[derive(Debug, Clone)]
pub struct Intersectable {
    intersectable_type: IntersectableType,
}

impl Intersectable {
    pub fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection> {
        match self.intersectable_type {
            IntersectableType::Sphere => self.local_intersect_sphere(ray, object),
            IntersectableType::Plane => self.local_intersect_plane(ray, object),
            _ => Vec::new(),
        }
    }

    fn local_intersect_sphere(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection> {
        ...sphere specific code
    }

    fn local_intersect_plane(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection> {
        ...plane specific implementation
    }
}

这很好用,但感觉非常不生锈。我在使用其他实现时遇到了一些问题: - 使用Box&lt;Intersectable&gt;(当它是Trait,而不是结构时)很难克隆(我复制了How to clone a struct storing a boxed trait object?,但不喜欢使用'static,因为这使得并发不可能)。 - 使用Arc&lt;Intersectable&gt; 似乎和Box 有同样的问题,尽管也许有办法让它工作。

有没有办法在 Rust 中做到这一点,让我能够利用并发性而不是像这样编写手动静态调度?

【问题讨论】:

  • 您能否展示您迄今为止尝试过的特征方法的功能示例,以便我们了解您遇到的问题?这比我们从头开始要容易得多。
  • 是的,我已经添加了之前的主要实现!
  • 也许你可以在你的形状中存储一个函数指针fn(&amp;Ray, Arc&lt;Shape&gt;) -&gt; Vec&lt;Intersection&gt;。我相信fnClone + Send。本质上,这就是您已经在对空结构进行动态调度所做的事情。
  • 这是一个非常有趣的概念,我没有想到,我会试一试并报告!
  • 哈,我现在也在!但有点不太先进。苦苦思索如何从我的球体中提取形状。

标签: rust


【解决方案1】:

我也在做“光线追踪器挑战”,不过比你落后一点。我没有并发的想法。我现在尝试遵循A-Frame ECS 的想法:

pub trait Primitive {}

pub struct Shape<T: Primitive> {
    pub transformation: M4x4,
    pub material: Material,
    pub primitive: T,
}

pub struct Sphere;
impl Primitive for Sphere {}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-30
    • 1970-01-01
    • 2022-10-05
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    相关资源
    最近更新 更多