Расширенные черты в коллекциях
У меня есть простая черта Fruit
и расширенная черта WeightedFruit
, Компилятор Rust принимает Fruit
черта в LinkedList
но нет WeightedFruit
в BTreeSet
, Что нужно изменить, чтобы отсортированный набор работал?
pub trait Fruit { }
pub trait WeightedFruit: Fruit + Ord { }
pub fn main() {
let unsorted: LinkedList<Box<Fruit>> = LinkedList::new();
let sorted: BTreeSet<Box<WeightedFruit>> = BTreeSet::new();
}
Сообщения об ошибках:
the trait `WeightedFruit` cannot be made into an object
trait `WeightedFruit: std::cmp::Ord` not satisfied
...
1 ответ
pub trait WeightedFruit: Fruit + Ord { }
Это говорит о каждой структуре, которая реализует WeightedFruit
должен быть сопоставим с собой. Но не для других структур, которые реализуют эту черту. Так что если Apple
инвентарь WeightedFruit
, это будет сопоставимо с Apple
, если Orange
инвентарь WeightedFruit
, это будет сопоставимо с Orange
но не друг другу.
Вы не можете создать коллекцию "всего, что является WeightedFruit", потому что они не являются взаимозаменяемыми - яблоки и апельсины различны, потому что каждый из них сопоставим разного вида.
Вместо этого вы хотите сделать что-то вроде этого:
use std::cmp::*;
use std::collections::*;
pub trait Fruit { }
pub trait WeightedFruit: Fruit {
fn weight(&self) -> u32;
}
impl Ord for WeightedFruit {
fn cmp(&self, other: &Self) -> Ordering {
self.weight().cmp(&other.weight())
}
}
impl PartialOrd for WeightedFruit {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for WeightedFruit {
fn eq(&self, other: &Self) -> bool {
self.weight() == other.weight()
}
}
impl Eq for WeightedFruit {}
struct Apple {
weight: u32
}
impl Fruit for Apple {}
impl WeightedFruit for Apple {
fn weight(&self) -> u32 {
self.weight
}
}
struct Orange {
weight: u32
}
impl Fruit for Orange {}
impl WeightedFruit for Orange {
fn weight(&self) -> u32 {
self.weight
}
}
pub fn main() {
let unsorted: LinkedList<Box<Fruit>> = LinkedList::new();
let sorted: BTreeSet<Box<WeightedFruit>> = BTreeSet::new();
}
Это говорит о том, что каждый WeightedFruit
плод должен быть в состоянии обеспечить его weight
и каждый WeightedFruit
можно сравнить с любым другим WeightedFruit
используя это weight
, Теперь вы можете сделать черты объектов из WeightedFruit
и смешать их вместе в коллекциях, потому что они взаимозаменяемы.
Дополнительное объяснение о Ord
и the trait ... cannot be made into an object
ошибка:
Когда вы работаете с объектами признаков, признаки выглядят как интерфейсы в ОО-языках. Вы можете иметь s trait и несколько структур, которые его реализуют, и функцию, которая принимает объект trait. Затем он может вызывать функции признака объекта, поскольку знает, что он будет иметь их, и что они абсолютно одинаковы для каждого объекта. Прямо как в ОО-языках.
Однако у черт есть еще одна особенность: они могут использовать Self
введите объявления функции. Self
всегда тот тип, который реализует черту. Если черта использует Self
в любой из своих функций он становится особенным и больше не может использоваться как объект черты. Каждый раз, когда структура реализует такую черту, она реализует другую версию (версия, где Self
это отличается). Вы не можете создать объект-черту, потому что каждая структура, которая его реализует, реализует свою версию.
Ord
в ржавчине это как Comparable<T>
в Яве, где T
выбран для вас компилятором. И так же, как вы не можете иметь метод, который принимает что-либо Comparable
в Java (надеюсь, вы не можете?), вы не можете иметь метод, который принимает любой Ord
черта объекта.