Why we can `impl` enums?

I am new to rust, so this question is just to help me understand to logic behind this, why can we implement functions to enums and make them store data??

how does an enum is different from a struct?, from what I see, the only difference is that enums allows us to group multiple "structs" under the same name

enum Message {
    Write(String)
}


impl Message {
    fn to_screen(&self) {
        match &self {
            Message::Write(m) => println!("{}", m),
        }
    }
}


fn main () {
    let my_message = Message::Write(String::from("Hello world"));
    my_message.to_screen();
}

and here is the same implementation but with structs

struct Message{
    text: String
}


impl Message {
    fn to_screen(&self) {
        println!("{}", self.text);
    }
}


fn main() {
    let my_message = Message{ text: String::from("Hello world") };
    my_message.to_screen();
}

Wrong question. ADTs existed since 1960th. Grandfather of all high-level languages ALGOL already had them more than half-century ago.

More interesting question is: how come today, in year 2023, these are not “ubiquition, present in all languages that people use”, but more of “strange constructs only present in some languages eggheads are using”.

The difference is that you may carry different values in different variants of enums.

This need is incredibly common. In particular the need to either have a value and don't have a value (Option in Rust-speak) or have something or error info (Result in Rust-speak) is literally something you find every ten lines or more often in Rust program.

You may consider struct a reduced version of enum with only one variant and simplified syntax.

3 Likes

In more simple terms a Struct is only one thing. But a enum can be any one of a number of things at different times.

For example:

    enum Animal {
        Cat,
        Dog,
        Hamster,
    }

As the Rust book says:

Where structs give you a way of grouping together related fields and data, like a Rectangle with its width and height , enums give you a way of saying a value is one of a possible set of values.

This is demonstrated by the fact that the example you gave uses match to check it has the Write variant. That is the only variant in your example but if you were dealing with my Animal enum you would need more arms on the match:

match &self {
            Animal::Cat => doDogThing(),
            Animal:: Dog => doCatThing(),
            Animal::Hamster => doHamsterThing(), 
}

Because it's incredibly powerful and useful.

I'm guessing you're familiar with C or something else that has fieldless enums; perhaps you're familiar with C-like unions too. Another way to describe Rust's enums is a "tagged union": It's a union but there's a tag (discriminant) to tell you which variant it is so you don't have to guess and inevitably get it wrong and cause UB. Moreover, Rust forces you to check by using a match or if let, etc. In this way the tagged union enum becomes a safe data structure to manipulate.

4 Likes

You can impl any data type that you own - structs, enums, and unions. std can even impl on primitives, for example i32 - Rust.

Enums are just a data type that happens to have some more meaning. If you have:

enum MyEnum {
    S(&str),
    F(f32),
    I(i32),
}

Then in C, the equivalent is more or less:

// Holds the enum's "overlapping" data with no tags
union MyEnumData {
    char* s;
    float f;
    int32_t i;
}

// Tells the variant of the enum
enum MyEnumTag {S, F, I}

// Rust enum = tag + data
struct MyEnum {
    enum MyEnumTag tag;
    union MyEnumData data;
}

So you can almost think of rust enums as just fancy sugar to create a special struct - and then you just impl that :slight_smile:

1 Like

"Implementing functions" does not necessarily require storage in the enums, nor any other types for which you impl traits. It’s extrusive. You can even impl YourTrait for i32 or for () if you like.

I think the OP was asking two questions:

  • Why enums can have behaviour?
  • Why enum variants can have data?

Why couldn't we?

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.