我正在研究和试验使用rust 。
我想实现一个抽象的火车“GraphEntity”,然后再实现两个特征“Point”和“Triangle”。
我有以下代码可以正常工作:
use std::cmp::Ordering;
trait GraphEntity {
fn plot (&self) {
println!("this is a plot!");
}
}
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
impl Ord for Point {
fn cmp(&self, other: &Self) -> Ordering {
(self.x, &self.y).cmp(&(other.x, &other.y))
}
}
impl PartialOrd for Point {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for Point {
fn eq(&self, other: &Self) -> bool {
(self.x, &self.y) == (other.x, &other.y)
}
}
impl Eq for Point { }
#[derive(Debug)]
struct Triangle {
x: i32,
y: i32,
z: i32,
}
impl GraphEntity for Point {
fn plot (&self) {
println!("P:[{},{}]", self.x, self.y);
}
}
impl GraphEntity for Triangle {
fn plot (&self) {
println!("T:[{},{},{}]", self.x, self.y,self.z);
}
}
struct SetOfEntities {
list: Vec<Box<dyn GraphEntity>>,
}
impl SetOfEntities {
fn new () -> Self {
Self {
list: Vec::new(),
}
}
fn append<S: GraphEntity + 'static>(&mut self, entity: S) -> &mut Self {
self.list.push(Box::new(entity));
self
}
fn plot(self) {
for x in self.list {
x.plot();
}
}
}
fn main() {
let p1: Point = Point { x: 1, y: 0 };
let p2: Point = Point { x: -1, y: 2 };
let t: Triangle = Triangle { x: 1, y: 2, z: 3};
let mut set = SetOfEntities::new();
set.append(p1);
set.append(p2);
set.append(t);
set.plot();
}
我现在想更改附加功能并检查列表中是否已存在任何现有点。如果它已经存在,我不会添加到列表中。
fn append<S: GraphEntity + 'static>(&mut self, entity: S) -> &mut Self {
match self.list.binary_search(&entity) {
Ok(pos) => self,
Err(pos) => { self.list.push(Box::new(entity)); self },
}
}
这给了我以下错误:error[E0308]: mismatched types
--> src/main.rs:70:39
|
69 | fn append<S: GraphEntity + 'static>(&mut self, entity: S) -> &mut Self {
| - this type parameter
70 | match self.list.binary_search(&entity) {
| ^^^^^^^ expected struct `std::boxed::Box`, found type parameter `S`
|
= note: expected reference `&std::boxed::Box<dyn GraphEntity>`
found reference `&S`
error[E0277]: the trait bound `dyn GraphEntity: std::cmp::Ord` is not satisfied
--> src/main.rs:70:39
|
70 | match self.list.binary_search(&entity) {
| ^^^^^^^ the trait `std::cmp::Ord` is not implemented for `dyn GraphEntity`
|
= note: required because of the requirements on the impl of `std::cmp::Ord` for `std::boxed::Box<dyn GraphEntity>`
知道如何纠正这个问题吗?
最佳答案
试图修复错误
你有两个错误:
expected struct 'std::boxed::Box', found type parameter 'S'
. binary_search
函数从 self.list
开始需要一个框是 Vec
的盒子。您可以将其更改为 self.list.binary_search(&Box::new(entity))
. (您可能仍然需要帮助编译器将其强制为 dyn 类型。)binary_search
需要实现 Ord
的对象trait,但它只知道 GraphEntity
因为对象的类型是dyn GraphEntity
.对于大多数特征,您可以给出
GraphEntity
一个 super 特征,这将被修复,但不幸的是,这在这里不起作用,因为您无法为 Ord
创建特征对象.你会得到错误 E0038 ,因为这可能不安全。我的小修复想法是创建一个
cmp
GraphEntity
中的函数并使用 binary_search_by
而不是 binary_search
.然而cmp
会有 Self
参数,这会导致相同的错误。据我所知,你无法按照你想要的方式修复它。 如果您无法在 Rust 中修复您的代码,那么代码的逻辑通常会出现问题。我认为这里就是这种情况,因为对于
binary_search
你需要比较dyn GraphEntity
对象。所以你还想比较 Point
与 Triangle
,它们没有(部分)顺序关系。使用枚举
您可能会注意到,Rust 的动态调度不是为(某些)复杂情况而设计的。比较不同类型的对象并非易事。实现相同的特征并没有说明比较它们。
如果
binary_search
超过 GraphEntity
objects 正是您想要的,而不是最好的解决方案可能是使用枚举。 Rust 将确保您处理比较不同类型的每种情况。比较函数可能如下所示:
fn cmp(&self, other: &GraphEntity) -> Ordering {
match (self,other) {
(GraphEntity::Point(p1),GraphEntity::Point(p2))
=> (p1.x, p1.y).cmp(&(p2.x, p2.y)),
(GraphEntity::Triangle(t1),GraphEntity::Triangle(t2))
=> (t1.x, t1.y, t1.z).cmp(&(t2.x, t2.y, t2.z)),
(GraphEntity::Point(_),GraphEntity::Triangle(_))
=> Ordering::Less,
(GraphEntity::Triangle(_),GraphEntity::Point(_))
=> Ordering::Greater,
}
}
如果 GraphEntity
中有更多变体,这会变得非常复杂。枚举,但它可以处理复杂性。而动态调度在处理模块化方面更好。似乎您试图将您的程序建模为使用基于继承的 OOP 语言(如 Java 或 C++)。小心,这是很多 Rust 初学者都会犯的错误,包括我自己。
关于rust - 在带有 rust 的向量中实现特征的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64169075/