【发布时间】: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<Intersectable>(当它是Trait,而不是结构时)很难克隆(我复制了How to clone a struct storing a boxed trait object?,但不喜欢使用'static,因为这使得并发不可能)。
- 使用Arc<Intersectable> 似乎和Box 有同样的问题,尽管也许有办法让它工作。
有没有办法在 Rust 中做到这一点,让我能够利用并发性而不是像这样编写手动静态调度?
【问题讨论】:
-
您能否展示您迄今为止尝试过的特征方法的功能示例,以便我们了解您遇到的问题?这比我们从头开始要容易得多。
-
是的,我已经添加了之前的主要实现!
-
也许你可以在你的形状中存储一个函数指针
fn(&Ray, Arc<Shape>) -> Vec<Intersection>。我相信fn是Clone + Send。本质上,这就是您已经在对空结构进行动态调度所做的事情。 -
这是一个非常有趣的概念,我没有想到,我会试一试并报告!
-
哈,我现在也在!但有点不太先进。苦苦思索如何从我的球体中提取形状。
标签: rust