Rust Dynami c отправка по признакам с универсальными c параметрами - PullRequest
0 голосов
/ 25 апреля 2020

У меня есть следующая Rust Playground постоянная ссылка

, что из моих следующих Трассировка лучей в выходные .

В момент реализации материалов я решил создать черту Material.

Я думал, что объекты в мире будут иметь атрибут material и луч Hit Hit может посмотреть на объект и запросить материал по запросу. Это хорошо работает для моей черты Normal, которая следует за подобным мышлением. Я реализовал все это с помощью динамической c отправки, хотя я думаю, что у меня достаточно asp, чтобы сделать это статически и с границами черт.

В связанном коде вы видите строку 13, я запрашиваю эти которые реализуют Normal, имеют метод, который будет возвращать Material. Тогда это говорит о том, что теперь Normal больше не может быть объектом черты error[E0038]: the trait Обычный cannot be made into an object

Если я правильно понимаю из таких вопросов, как это , кажется, что, поскольку дженерики мономорфизированы ли среда выполнения Rust, возможно, не утечка подходящего метода для material, учитывая, что якобы может быть один для каждого типа, реализующего Normal? Это меня не совсем устраивает, так как кажется, что, поставив в то же положение, что и среда выполнения Rust, я мог бы взглянуть на тот инструмент реализации Normal, который у меня под рукой, скажем Sphere и сказать, что я будет выглядеть в таблице Sphere. Не могли бы вы объяснить, где я здесь не прав?

Оттуда я попытался просто бороться с компилятором и отправился на stati c dispatch. линии 17-21

struct Hit<'a> {
    point: Vec3,
    distance: f32,
    object: &'a dyn Normal,
}

стали

struct Hit<'a, T: Normal> {
    point: Vec3,
    distance: f32,
    object: &'a T,
}

, и оттуда я остаюсь, пытаясь заткнуть отверстие за отверстием так, что кажется, что конца не видно.

Какие варианты дизайна я могу сделать по-другому, помимо изучения того, что в корне не так с моим нынешним пониманием?

Ответы [ 2 ]

1 голос
/ 25 апреля 2020

Возможно, я что-то упускаю, но я думаю, что вы могли бы - по крайней мере из того, что я видел, - идти дальше по вашему пути.

Я думаю, вы могли бы изменить эту функцию:

fn material<T: Material>(&self) -> T;

В том виде, в каком оно стоит, он говорит: Любой Normal предлагает функцию material, где вызывающий абонент может указать Material, который будет возвращать функция.

Но (я думаю, ) вы хотите указать следующее: любой Normal имеет материал, который может быть запрошен вызывающим абонентом. Но вызывающая сторона не имеет права диктовать любые Material, которые будут возвращены. Чтобы перевести это в код, вы можете указать:

fn material(&self) -> &dyn Material;

Это говорит о том, что material возвращает Material (как объект-признак).

Тогда Sphere может реализовать Normal:

impl<'a> Normal for Sphere<'a> {
    fn normal(&self, point: &Vec3) -> Ray {
        Ray::new(point, &(point - &self.center))
    }
    fn material(&self) -> &dyn Material {
        self.material
    }
}

Ссылка на игровую площадку.

1 голос
/ 25 апреля 2020

, помещенный в то же положение, что и среда выполнения Rust, я мог бы посмотреть на тот момент, когда у меня есть обычный инструмент реализации, скажем Сфера, и сказать, что я посмотрю в таблице Сферы

За исключением того, что среда выполнения Rust здесь ничего не может сделать.

Фактически, Rust не имеет среды выполнения в смысле "что-то, выполняющее код". Среда выполнения Rust выполняет только задачу настройки и очистки, но пока поток управления находится где-то внутри вашей функции main, вы работаете самостоятельно (а в средах no_std даже этого не будет). Таким образом, каждая динамическая отправка c должна быть включена в тип, поместив указатель vtable рядом с указателем данных - см. эту документацию для получения более подробной информации.

Но, поскольку дженерики, как вы уже заявили, мономорфизированы, не будет одного fn material для каждой реализации Normal: будет неизвестное, потенциально бесконечное семейство этих функций, по одному для каждого типа, реализующего Material , Обратите внимание на «неизвестный, потенциально бесконечный» бит: поскольку вы не можете утекать приватные части, если признак Normal опубликован c, признак Material также должен быть опубликован c - и тогда ничто не помешает Пользователь вашего кода, чтобы добавить другую реализацию Material, не известную вашему коду, которая просто не может быть включена в vtable таблицы dyn Normal.

Именно поэтому методы generi c не являются объектно-безопасными , Они не могут вписаться в vable-объект trait, поскольку мы не знаем их всех при создании объекта trait.

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