Conflicting feature implementations, even if related types differ

I am trying to create a generic structure that wraps isize or AtomicIsize , but I am AtomicIsize error when I try to implement a trait for both possible implementations of the structure. I created a minimal example that demonstrates my problem below.

 use std::sync::atomic::{AtomicIsize, Ordering}; use std::ops::Deref; use std::marker::PhantomData; pub trait Counted { fn inc(&self, value: isize); } pub type PlainCounter = isize; pub type AtomicCounter = AtomicIsize; pub struct Counter<'a, T: 'a> { counter: T, phantom: PhantomData<&'a T>, } impl<'a, T> Counter<'a, T> where T: Deref<Target = PlainCounter> { pub fn new(counter: T) -> Self { Counter { counter: counter, phantom: PhantomData, } } } impl<'a, T> Counted for Counter<'a, T> where T: Deref<Target = PlainCounter> { fn inc(&self, value: isize) { self.counter += 1; } } impl<'a, T> Counter<'a, T> where T: Deref<Target = AtomicCounter> { pub fn new(counter: T) -> Self { Counter { counter: counter, phantom: PhantomData, } } } impl<'a, T> Counted for Counter<'a, T> where T: Deref<Target = AtomicCounter> { fn inc(&self, value: isize) { self.counter.fetch_add(value, Ordering::SeqCst); } } 

( playground )

The error I am getting is that the compiler found conflicting implementations of trait `Counted` for type `Counter<'_, _>` . It seems that the compiler cannot determine that the implementations are for two different types of T , namely T: Deref<Target = PlainCounter> and T: Deref<Target = AtomicCounter> . Maybe there is a way to provide additional information to the compiler so that it can distinguish between two cases, or am I on the wrong track entirely?

+7
source share
2 answers

You can execute this template by specifying the second attribute that does the actual work, and implemented for (Counter<'a, T>, <T as Deref>::Target) , and output the Counter trait for this implementation.

I don’t think it was very clear, but I think the example can illustrate well. Using the shorter Shepmaster example for clarity, we proceed from this:

 use std::ops::Deref; trait Foo {} impl<T> Foo for T where T: Deref<Target = u8> {} impl<T> Foo for T where T: Deref<Target = bool> {} fn main() {} 

:

 use std::ops::Deref; trait Foo {} trait InnerFoo {} impl<T> Foo for T where T: Deref, (T, <T as Deref>::Target): InnerFoo {} impl<T> InnerFoo for (T, u8) {} impl<T> InnerFoo for (T, bool) {} fn main() {} 
+8
source

Unfortunately, this is not yet implemented in the language.

Here is the tracking issue: rust-lang / rust # 2400 .

RFC rust-lang / rfcs # 1672 was also proposed to solve this problem, but then was delayed pending integration with Chalk , which will facilitate implementation.

In the meantime, you will have to use the workaround suggested above .

+2
source

Source: https://habr.com/ru/post/1011966/


All Articles