Why doesn't this work:
trait Update {
fn update(&mut self);
}
trait A {}
trait B {}
impl<T: A> Update for T {
fn update(&mut self) {
println!("A")
}
}
impl<U: B> Update for U {
fn update(&mut self) {
println!("B")
}
}
error[E0119]: conflicting implementations of trait `Update`:
--> src/main.rs:14:1
|
8 | impl<T: A> Update for T {
| ----------------------- first implementation here
...
14 | impl<U: B> Update for U {
| ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
I would assume it is checked later if types overlap.
Implementing a trait on a type is similar to implementing regular methods. The difference is that after impl , we put the trait name we want to implement, then use the for keyword, and then specify the name of the type we want to implement the trait for.
What are blanket implementations? Blanket implementations leverage Rust's ability to use generic parameters. They can be used to define shared behavior using traits. This is a great way to remove redundancy in code by reducing the need to repeat the code for different types with similar functionality.
Trait and lifetime bounds provide a way for generic items to restrict which types and lifetimes are used as their parameters. Bounds can be provided on any type in a where clause.
Rust is a systems programming language with a concept of Interfaces in Rust that is implemented by Traits. Trait in Rust is basically a struct having no bodies for the methods. The logic is generally not defined but only the methods are.
What would you expect the output of this program to be?
struct AAndB {}
impl A for AAndB {}
impl B for AAndB {}
let a_and_b = AAndB {};
a_and_b.update();
There is an unstable compiler feature, specialization, which you can enable in nightly builds, which lets you have overlapping instances, and the most "specialized" is used.
But, even with specialization enabled, your example won't work because A
and B
are completely equivalent so you could never unambiguously pick an instance.
As soon as there is an obviously "more specialized" instance, it will compile and work as expected - provided you are using a nightly build of Rust with specialization enabled. For example, if one of the traits is bounded by the other, then it is more specialized, so this would work:
#![feature(specialization)]
trait Update {
fn update(&mut self);
}
trait A {}
trait B: A {}
impl<T: A> Update for T {
default fn update(&mut self) {
println!("A")
}
}
impl<U: B> Update for U {
fn update(&mut self) {
println!("B")
}
}
Specifying the implementation method as default
allows another more specific implementation to define its own version of the method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With