繁体   English   中英

在带锈病的向量中实现特征的问题

[英]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>`

知道如何纠正这个问题吗?

尝试修复错误

你有两个错误:

  1. 第一个问题很容易解决: expected struct 'std::boxed::Box', found type parameter 'S' binary_search函数需要一个盒子,因为self.list是一个盒子的Vec 您可以将其更改为self.list.binary_search(&Box::new(entity)) (您可能仍然需要帮助编译器将其强制为 dyn 类型。)
  2. 第二个错误有点棘手,很难解决。 问题是binary_search需要实现Ord trait 的对象,但它只知道GraphEntity因为对象的类型是dyn GraphEntity 对于大多数特征,您可以给GraphEntity一个超特征,这将被修复,但不幸的是,这在这里不起作用,因为您无法为Ord制作特征对象。 您会收到错误E0038 ,因为这可能不安全。 我的小修复想法是在GraphEntity创建一个cmp函数并使用binary_search_by而不是binary_search 但是cmp会有一个Self参数,这会导致相同的错误。 所以据我所知,你不能按照你想要的方式修复它。

如果你不能在 Rust 中修复你的代码,那么代码的逻辑经常会出现问题。 我认为这里就是这种情况,因为对于binary_search您需要比较dyn GraphEntity对象。 因此,您还想将PointTriangle进行比较,后者没有(部分)顺序关系。

使用枚举

您可能会注意到,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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM