Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there some way to implement a trait on multiple traits?

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.

like image 563
porky11 Avatar asked Feb 23 '17 21:02

porky11


People also ask

How do you implement traits?

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 is a blanket implementation?

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.

What are trait bounds?

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.

Are Rust traits interfaces?

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.


1 Answers

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.

like image 147
Peter Hall Avatar answered Sep 25 '22 02:09

Peter Hall