Rust's enums are algebraic datatypes. As far as I can tell this seems to subsume what struct is. What is different about struct that necessitates keeping it?
4 Answers
First of all, you are correct that semantically enum
is strictly superior to the struct
as to what it can represent, and therefore struct
is somewhat redundant.
However, there are other elements at play here.
ease of use: the values within an
enum
can only be accessed (directly) through matching; contrast with the ease of use of accessing astruct
field. You could write accessors for each and every field, but that is really cumbersome.distinction: an
enum
is a tagged union, astruct
has a fixed-layout; we (programmers) generally like to put labels on things, and therefore giving different names to different functionality can be appreciated.
As I see it, struct
is therefore syntactic sugar. I usually prefer lean and mean, but a bit of sugar can go a long way in increasing what can be represented tersely.
Firstly, Rust has a wide array of data types:
- Structs with named fields (
struct Foo {bar: uint}
) - Tuple structs (
struct Foo(pub Bar, Baz)
) - Structs with no fields (
struct Foo;
) - Enums, with various types of variants:
- Variants with no fields (eg
None
) - Tuple variants (eg
Some(T)
) - Struct variants (eg
Some { pub inner :T }
)
- Variants with no fields (eg
This gives the programmer some flexibility in defining datatypes. Often, you don't want named fields, especially if the struct/variant has only one field. Rust lets you use tuple structs/tuple variants in that case.
If structs were removed from Rust there would be no loss of functionality, enums with struct variants could be used again. But there would be an overwhelming number of single-variant enums which would be unnecessary and cumbersome to use.
Not 100% correct, but another nice way to think about it : enum
isn't actually superior to struct
, the syntax sugar just makes it look like it is.
An enum
is a sum type meaning that it's value is one value of one of a set of other types. The Result<T, E>
type is either of type T
or E
. So each enum
variant has exactly one type associated with it. Everything else (no type, tuple variants and struct variants) could be syntax sugar.
enum Animal {
// without syntax sugar
Cat(i32),
// desugars to `Dog(())` (empty tuple/unit)
Dog,
// desugars to `Horse((i32, bool))` (tuple)
Horse(i32, bool),
// desugars to `Eagle(GeneratedEagleType)` and a struct definition outside
// of this enum `struct GeneratedEagleType { weight: i32, male: bool }`
Eagle { weight: i32, male: bool }
}
So it would be enough if each enum
variant would be associated with exactly one type. And in that case enum
is not superior to struct
, because it cannot construct product types (like struct
).
To be able write the "type definition" inside the enum variant definition is just for convenience.
Also: struct
is superior to "tuple structs" and "tuples", too. If we ignore the names those three things are nearly equivalent. But Rust still has those three different kinds of types for convenience.
Please note that I don't know if those enum definitions are actually syntax sugar or not. But they could be and that might help think about. it