[英]problem implementing a trait in a vector with rust
我正在研究和试验 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();
}
我现在想更改 append 函数并检查列表中是否已存在任何现有点。 如果它已经存在,我不会添加到列表中。
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
一个超特征,这将被修复,但不幸的是,这在这里不起作用,因为您无法为Ord
制作特征对象。 您会收到错误E0038 ,因为这可能不安全。 我的小修复想法是在GraphEntity
创建一个cmp
函数并使用binary_search_by
而不是binary_search
。 但是cmp
会有一个Self
参数,这会导致相同的错误。 所以据我所知,你不能按照你想要的方式修复它。 如果你不能在 Rust 中修复你的代码,那么代码的逻辑经常会出现问题。 我认为这里就是这种情况,因为对于binary_search
您需要比较dyn GraphEntity
对象。 因此,您还想将Point
与Triangle
进行比较,后者没有(部分)顺序关系。
您可能会注意到,Rust 的动态调度不是为(某些)复杂情况设计的。 比较不同类型的对象并非易事。 实现相同的特征并没有说明要比较它们。
如果binary_search
超过GraphEntity
对象正是你想要的,不是最好的解决办法可能是使用枚举。 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 初学者都会犯的错误,包括我自己。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.