如何解决特质通用实现(空白实现)的冲突?

时间:2019-01-10 10:54:09

标签: generics rust traits

我来自C ++,并且遇到通用特征隐含的问题。

我正在尝试构建一个对多边形和开放路径都执行一些操作的几何库,但是每种情况下的行为略有不同。理想情况下,我希望将几何运算的一种实现作为一种方法来查询其操作的对象以获取标志。

我还希望该库可用于任何看起来像多边形或开放路径的对象,而不仅仅是我的数据类型,因此我希望PolygonLikeOpenPathLike的特征可以在任意种类。我有看起来像这样的代码:

trait Clipable {
    fn closed() -> bool;
    fn geom_func(&self) {
        if Self::closed() {
            println!("closed");
        } else {
            println!("open");
        }
    }
}

trait PolygonLike {}
trait OpenPathLike {}

struct Point(f64, f64);
type PointVec = Vec<Point>;
struct Poly(PointVec);
struct Path(PointVec);

impl PolygonLike for Poly {}
impl OpenPathLike for PointVec {}

impl<T> Clipable for T
where
    T: PolygonLike,
{
    fn closed() -> bool {
        true
    }
}

impl<T> Clipable for T
where
    T: OpenPathLike,
{
    fn closed() -> bool {
        false
    }
}

fn main() {
    let pg = Poly(PointVec::new());
    let op = Path(PointVec::new());
    pg.geom_func();
    op.geom_func();
}

代码无法编译为:

error[E0119]: conflicting implementations of trait `Clipable`:
  --> src/main.rs:28:1
   |
24 | impl<T> Clipable for T where T: PolygonLike {
   | ------------------------------------------- first implementation here
...
28 | impl<T> Clipable for T where T: OpenPathLike {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation

我在其他地方读到,尽管没有类型同时实现wherePolygonLike,但冲突检查程序并未使用OpenPathLike子句。

我知道这是因为消费者可以同时实现这些特征并破坏库。我没有得到的是如何解决这个问题。

我还看到了其他人使用新类型限制通用实现的文章,但我不知道如何使它适合我的情况。

1 个答案:

答案 0 :(得分:4)

目前无法实现。您将需要分别为ClipablePoly和任何其他实施PointVec

您可以考虑编写宏以减少重复性:

macro_rules! clipable_poly {
    ($($ty: ty),+) => {
        $(
            impl PolygonLike for $ty {}

            impl Clipable for $ty {
                fn closed() -> bool {
                    true
                }
            }
        )+
    }   
}

macro_rules! clipable_open {
    ($($ty: ty),+) => {
        $(
            impl OpenPathLike for $ty {}

            impl Clipable for $ty {
                fn closed() -> bool {
                    false
                }
            }
        )+
    }   
}

clipable_poly!(Poly, Point);
clipable_open!(PointVec, Path);