Идиоматический способ структурирования черты ржавчины - PullRequest
0 голосов
/ 09 марта 2019

Я писал Ray Caster в Rust после «The Ray Tracer Challenge», и мне было трудно найти правильный способ реализации полиморфизма в Rust.Мои приоритеты в том, чтобы объект можно было использовать в многопоточной программе, и это, кажется, главная проблема.

У меня есть два случая на этом, но я сосредоточусь на одном: форма.Существуют разные виды фигур (придерживаясь суффикса able, который я изначально называл своей чертой Intersectable).Здесь была реализация объекта рабочей черты, но она не работала с многопоточностью:

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

Как чистая структура, без официального полиморфизма, я написал своего рода статическую диспетчеризацию, которая выглядит какthis:

#[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> (когда это была черта, а не структура), трудно клонировать (я скопировал Как клонировать структуру, хранящую объект черты в штучной упаковке? но ему не нравилось использовать static, поскольку это делало параллелизм невозможным).- Использование Arc<Intersectable>, похоже, имело те же проблемы, что и Box, хотя, возможно, есть способ сделать эту работу.

Есть ли способ сделать это в Rust, который позволяет мне использовать преимущества параллелизмаа не писать ручную статическую рассылку вот так?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...