Calling a method depending on Enum value


#1

Hi all,

Is there a way to call a method from a struct, depending on an Enum value ?

For example:

enum Color {
     Black,
     White
}

let v: MyStruct<Color::Black> = MyStruct::new();

v.my_method_depending_on_enum_value();
 

This construct is not allowed, because it claims an Enum type.

A match statement will make it, but I’d like to make it possible using generics, and traits (but I can’t find a way to code it).

I’d appreciate any help. Thanks in advance !


#2

If you want to know precisely what is inside an object, then enums are not a good choice because they are dynamic (known at run time).

What you could do is to have two separate types:

struct White;
struct Black;

struct MyStruct<C> {
    color: C,
    /* ... */
}

impl MyStruct<White> {
    fn my_method_depending_on_enum_value(&self) { println!("White"); }
}

impl MyStruct<Black> {
    fn my_method_depending_on_enum_value(&self) { println!("Black"); }
}

let v: MyStruct<Black> = MyStruct { color: Black, /* ... */ };

v.my_method_depending_on_enum_value();

This works, but the limitation is that you cannot abstract over C. If you do need to abstract over C, the two methods need to be unified under a common trait:

struct White;
struct Black;

struct MyStruct<C> {
    color: C,
    /* ... */
}

trait Color {
    fn my_method_depending_on_enum_value(&self);
}

impl Color for MyStruct<White> {
    fn my_method_depending_on_enum_value(&self) { println!("White"); }
}

impl Color for MyStruct<Black> {
    fn my_method_depending_on_enum_value(&self) { println!("Black"); }
}

fn example<C>(color: C) where MyStruct<C>: Color {
    let v: MyStruct<C> = MyStruct { color: color, /* ... */ };

    v.my_method_depending_on_enum_value();
}

#3

At the moment you’re stuck using Trait Objects instead, like so:

trait Color {
    fn my_method_depending_on_implementor(&self) -> ();
}

struct Black {}
struct White {}

impl Color for Black {
    fn my_method_depending_on_implementor(&self) -> () {
        println!("I am black!");
    }
}
impl Color for White {
    fn my_method_depending_on_implementor(&self) -> () {
        println!("I am white!");
    }
}
fn main() {
    let v = Black {};
    let w:&Color = &v
    w.my_method_depending_on_implementor();
}

It would be kind of nice to have an enum be able to specify a trait that all its variants are required to implement, with v.method() shorthand for matching on enum type, but that’s not how it works right now.

Anyone want to help me draft an RFC? :slight_smile:


#4

Thanks all for your help. I finally succeeded to implement a trait with 2 empty structs.

@shrydar: I don’t think this is possible, because enums as a whole is a type, not its individual values.


#5

https://github.com/rust-lang/rfcs/pull/1450 might be of interest.