Maleware
Maleware

Reputation: 31

Trait bounds did not work out for enums as generic parameter

For a larger Programm, I've tried to introduce a new trait to pass some different enums through a function.

We got this situation:

enum One { One, Two}
enum Two {Three, Four}

I used a trait like this:

pub trait NewTrait {}

Then:

impl NewTrait for One {}
impl NewTrait for Two {}

then we have a function:

fn foo<T: NewTrait> (test: T) {
match test{
    One::One => println!("One"),
    One::Two => println!("Two"),
    Two::Three => println!("Three"),
    Two::Four => println!("Four"),
    }
}

We use:

fn main() {
    foo(One::One);
    foo(Two::Three);
}

Then I got this errormessage:

Compiling Examplecode v0.1.0 (/Users/maximilianwittich/projects/Examplecode)
error[E0308]: mismatched types
  --> src/main.rs:18:9
   |
9  | enum One { One, Two}
   |            --- unit variant defined here
...
16 | fn foo<T: NewTrait>(test: T) {
   |        - this type parameter
17 |     match test{
   |           ---- this expression has type `T`
18 |         One::One => println!("One!"),
   |         ^^^^^^^^ expected type parameter `T`, found enum `One`
   |
   = note: expected type parameter `T`
                        found enum `One`

error[E0308]: mismatched types
  --> src/main.rs:19:9
   |
9  | enum One { One, Two}
   |                 --- unit variant defined here
...
16 | fn foo<T: NewTrait>(test: T) {
   |        - this type parameter
17 |     match test{
   |           ---- this expression has type `T`
18 |         One::One => println!("One!"),
19 |         One::Two => println!("Two!"),
   |         ^^^^^^^^ expected type parameter `T`, found enum `One`
   |
   = note: expected type parameter `T`
                        found enum `One`

error[E0308]: mismatched types
  --> src/main.rs:20:9
   |
10 | enum Two {Three, Four}
   |           ----- unit variant defined here
...
16 | fn foo<T: NewTrait>(test: T) {
   |        - this type parameter
17 |     match test{
   |           ---- this expression has type `T`
...
20 |         Two::Three => println!("Three!"),
   |         ^^^^^^^^^^ expected type parameter `T`, found enum `Two`
   |
   = note: expected type parameter `T`
                        found enum `Two`

error[E0308]: mismatched types
  --> src/main.rs:21:9
   |
10 | enum Two {Three, Four}
   |                  ---- unit variant defined here
...
16 | fn foo<T: NewTrait>(test: T) {
   |        - this type parameter
17 |     match test{
   |           ---- this expression has type `T`
...
21 |         Two::Four => println!("Four!")
   |         ^^^^^^^^^ expected type parameter `T`, found enum `Two`
   |
   = note: expected type parameter `T`
                        found enum `Two`

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0308`.
error: could not compile `Examplecode`

Errormessage

Can anybody explain to me what's going on? Maybe with a bit brighter explanation, since I honestly try to learn to code in Rust.

Upvotes: 1

Views: 1485

Answers (1)

user4815162342
user4815162342

Reputation: 154886

I do not understand in particular what type of action I try to perform here? In other words, what should the trait provide to use the match switch?

Instead of attempting to match across all possibilities (which is impossible, as any number of types could implement the trait), your trait should provide the behavior you need in foo. For example:

// enum One and Two defined as in the question

pub trait NewTrait {
    fn display(&self);
}

impl NewTrait for One {
    fn display(&self) {
        match self {
            One::One => println!("One"),
            One::Two => println!("Two"),
        }
    }
}

impl NewTrait for Two {
    fn display(&self) {
        match self {
            Two::Three => println!("Three"),
            Two::Four => println!("Four"),
        }
    }
}

fn foo<T: NewTrait>(test: T) {
    test.display();
}

Playground

If you really insisted on matching all options, the trait could provide that as well, e.g. using a custom enum that squashes the existing enums:

// enum One and Two defined as in the question

enum Match {
    One,
    Two,
    Three,
    Four,
}

trait NewTrait {
    fn as_match(&self) -> Match;
}

impl NewTrait for One {
    fn as_match(&self) -> Match {
        match self {
            One::One => Match::One,
            One::Two => Match::Two,
        }
    }
}

impl NewTrait for Two {
    fn as_match(&self) -> Match {
        match self {
            Two::Three => Match::Three,
            Two::Four => Match::Four,
        }
    }
}

fn foo<T: NewTrait>(test: T) {
    match test.as_match() {
        Match::One => println!("One"),
        Match::Two => println!("Two"),
        Match::Three => println!("Three"),
        Match::Four => println!("Four"),
    }
}

Playground

It's hard to tell whether this makes any sense because we don't know the actual problem you're trying to solve. But hopefully it gives you an idea of what you can accomplish with traits and generics.

See also the chapter on traits in the book.

Upvotes: 1

Related Questions