I'm coming from C++ and I'm running into issues with generic trait implemntations.
I'm trying to build a geometry library that does some operation on both polygons and open paths, but behaves slightly different for each case. Ideally I want one implementation of a geometry operation as a method which can query the object it's operating on for a flag.
I also want this library to work on any object that can look like a polygon or open path, not just my data types, so I want traits for PolygonLike
and OpenPathLike
that can be implemented on any type. I have code that looks like this:
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();
}
The code fails to compile with:
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
I have read elsewhere that the where
clause isn't used by the conflict checker, even though no type implements both PolygonLike
and OpenPathLike
.
I get that this is because a consumer could just implement both those traits and break the library. What I don't get is how I can work around this.
I have seen other posts where people have used newtypes to limit generic implementations, but I can't figure out how to make that work for my scenario.
This is currently not possible. You will need to implement Clipable
for Poly
, PointVec
, and any others, individually.
You might consider writing macros to make this less repetitive:
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);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.