集合中的扩展特征
Extended Traits in Collections
我有一个普通特征 Fruit
和一个扩展特征 WeightedFruit
。 Rust 编译器接受 LinkedList
中的 Fruit
特征,但不接受 BTreeSet
中的 WeightedFruit
。应该更改什么以使排序集工作?
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
...
pub trait WeightedFruit: Fruit + Ord { }
这表示实现 WeightedFruit
的每个结构都必须与自身相比较。但不适用于实现该特征的其他结构。因此,如果 Apple
实现 WeightedFruit
,它将与 Apple
相媲美,如果 Orange
实现 WeightedFruit
,它将与 Orange
相媲美, 但不是彼此。
您不能构建 "anything that is 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
都可以使用此 [=20= 与任何其他 WeightedFruit
进行比较].现在您可以创建 WeightedFruit
的特征对象并将它们混合在集合中,因为它们可以互换。
关于 Ord
和 the trait ... cannot be made into an object
错误的补充说明:
当您使用特征对象时,特征看起来有点像 OO 语言中的接口。你可以有 s trait 和多个实现它的结构,以及一个接受 trait 对象的函数。然后它可以在对象上调用特征的函数,因为它知道它将拥有它们并且它们对于每个对象都是完全相同的。就像在 OO 语言中一样。
然而 traits 有一项额外的功能:它们可以在函数声明中使用 Self
类型。 Self
始终是实现特征的类型。如果特征在其任何函数中使用 Self
,它就会变得特殊并且不能再用作特征对象。每次结构实现这种特征时,它都会实现它的不同版本(Self
不同的版本)。您不能创建特征对象,因为实现它的每个结构都在实现它的不同版本。
rust 中的 Ord
就像 java 中的 Comparable<T>
,其中 T
是由编译器为您选择的。就像你不能有一个方法接受 java 中的任何东西 Comparable
(我希望你不能?),你不能有一个方法接受任何 Ord
特征对象。
我有一个普通特征 Fruit
和一个扩展特征 WeightedFruit
。 Rust 编译器接受 LinkedList
中的 Fruit
特征,但不接受 BTreeSet
中的 WeightedFruit
。应该更改什么以使排序集工作?
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
...
pub trait WeightedFruit: Fruit + Ord { }
这表示实现 WeightedFruit
的每个结构都必须与自身相比较。但不适用于实现该特征的其他结构。因此,如果 Apple
实现 WeightedFruit
,它将与 Apple
相媲美,如果 Orange
实现 WeightedFruit
,它将与 Orange
相媲美, 但不是彼此。
您不能构建 "anything that is 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
都可以使用此 [=20= 与任何其他 WeightedFruit
进行比较].现在您可以创建 WeightedFruit
的特征对象并将它们混合在集合中,因为它们可以互换。
关于 Ord
和 the trait ... cannot be made into an object
错误的补充说明:
当您使用特征对象时,特征看起来有点像 OO 语言中的接口。你可以有 s trait 和多个实现它的结构,以及一个接受 trait 对象的函数。然后它可以在对象上调用特征的函数,因为它知道它将拥有它们并且它们对于每个对象都是完全相同的。就像在 OO 语言中一样。
然而 traits 有一项额外的功能:它们可以在函数声明中使用 Self
类型。 Self
始终是实现特征的类型。如果特征在其任何函数中使用 Self
,它就会变得特殊并且不能再用作特征对象。每次结构实现这种特征时,它都会实现它的不同版本(Self
不同的版本)。您不能创建特征对象,因为实现它的每个结构都在实现它的不同版本。
rust 中的 Ord
就像 java 中的 Comparable<T>
,其中 T
是由编译器为您选择的。就像你不能有一个方法接受 java 中的任何东西 Comparable
(我希望你不能?),你不能有一个方法接受任何 Ord
特征对象。