Как использовать трейт-объект в BinaryHeap?

У меня есть следующий упрощенный код:

use std::collections::BinaryHeap;
use std::rc::Rc;

struct JobId;
struct Coord;
struct TimeStep;

pub trait HasJob {
    fn id(&self) -> JobId;
    fn start(&self) -> Coord;
    fn end(&self) -> Coord;
    fn earliest_start(&self) -> TimeStep;
    fn latest_finish(&self) -> TimeStep;
}

type JobPtr = Rc<HasJob>;

// a concrete class that implements the above trait
// and other basic traits like Eq, Hash, Ord, etc
pub struct Job {}
// another class that implements the HasJob trait
pub struct JobPrime {}

fn main() {
    // this line raises a compiler error
    let heap: BinaryHeap<JobPtr> = BinaryHeap::with_capacity(10);
}

Основная идея состоит в том, чтобы использовать (уникальные) id для заказа.

Инициализация кучи вызывает следующую ошибку:

error[E0277]: the trait bound `HasJob: std::cmp::Ord` is not satisfied
  --> src/main.rs:24:36
   |
24 |     let heap: BinaryHeap<JobPtr> = BinaryHeap::with_capacity(10);
   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `HasJob`
   |
   = note: required because of the requirements on the impl of `std::cmp::Ord` for `std::rc::Rc<HasJob>`
   = note: required by `<std::collections::BinaryHeap<T>>::with_capacity`

Я только начал пробовать свои силы в Rust и имею опыт работы с ООП/С++/Java. Намерение состоит в том, чтобы использовать трейт HasJob в качестве «интерфейса» и использовать его для вызова стирания/динамической отправки типов по отношению к общим коллекциям/контейнерам — общий шаблон ООП.

Если я правильно понимаю, общий параметр BinaryHeap имеет ограничение, что переданный ему конкретный тип должен реализовать черту Ord. Попытка расширить исходную черту требуемой чертой, например...

pub trait HasJob: Ord + /*others*/

... нарушает гарантию безопасности объектов Rust и вызывает следующую ошибку компилятора:

error[E0038]: the trait `HasJob` cannot be made into an object
  --> src/main.rs:16:22
   |
16 |     type JobPtr = Rc<HasJob>;
   |                      ^^^^^^ the trait `HasJob` cannot be made into an object
   |
   = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses

Как обойти вышеуказанную проблему?


person shadeMe    schedule 06.03.2018    source источник
comment
Возможно, вы захотите указать, действительно ли элементы в двоичной куче должны быть типаж-объектами и/или иметь подсчет ссылок. Какие конкретные реализации HasJob у вас есть?   -  person E_net4 the curator    schedule 06.03.2018
comment
Как упорядочить JobPtr, используя только id, start, end, earliest_start и latest_finish?   -  person trentcl    schedule 06.03.2018
comment
В основном то же самое, что и Как проверить равенство между типаж-объектами   -  person Shepmaster    schedule 06.03.2018
comment
@ E_net4 Есть только один конкретный импл. HasJob и просто возвращает значения соответствующих полей. Пример кода, который я разместил выше, — это всего лишь игрушечный пример, который я использовал, чтобы понять, как работает Rust. Объекты задания совместно используются в другом месте, поэтому я использовал указатель с подсчетом ссылок. Как бы то ни было, использование обычной ссылки вызывает те же ошибки.   -  person shadeMe    schedule 06.03.2018
comment
Кажется, вы выявили проблему XY. :) Только с одной конкретной реализацией вам не нужно использовать трейт-объекты.   -  person E_net4 the curator    schedule 06.03.2018
comment
@trentcl Код в значительной степени представляет собой игрушечный пример, но основная идея состоит в том, чтобы использовать (уникальные) идентификаторы для заказа.   -  person shadeMe    schedule 06.03.2018
comment
@ E_net4 Действительно - я это понимаю. Однако смысл упражнения состоял в том, чтобы написать код, исходя из предположения, что существует несколько реализаций. Как я упоминал ранее, код служит только для того, чтобы помочь мне понять, как работает язык.   -  person shadeMe    schedule 06.03.2018
comment
@Shepmaster Извините, но я не понимаю, как этот пост относится к моему вопросу. Не могли бы вы уточнить?   -  person shadeMe    schedule 06.03.2018
comment
@shadeMe Ответ Шепмастера на другой пост, относящийся к вашей проблеме: игровая площадка. Чтобы сравнить трейт-объекты HasJob, вы должны реализовать Ord для HasJob, а не только для типа, реализующего HasJob (поскольку невозможно сравнивать разные типы, даже если они оба реализуют Ord).   -  person trentcl    schedule 06.03.2018
comment
@trentcl А, я только что заметил, что он добавил свой ответ для трейт-объектов. Я не понимал, что таким образом можно реализовать супер-черты для черт. Помечено как дубликат, спасибо!   -  person shadeMe    schedule 06.03.2018