Enumerations - The Rust Reference

# Enumerations

> Syntax
> Enumeration :
> `enum` IDENTIFIER Generics? WhereClause? `{` EnumItems? `}`

> EnumItems :
> EnumItem ( `,` EnumItem )* `,`?

> EnumItem :
> OuterAttribute* Visibility?
> IDENTIFIER ( EnumItemTuple | EnumItemStruct | EnumItemDiscriminant )?

> EnumItemTuple :
> `(` TupleFields? `)`

> EnumItemStruct :
> `{` StructFields? `}`

> EnumItemDiscriminant :
> `=` Expression

An enumeration, also referred to as enum is a simultaneous definition of a nominal enumerated type as well as a set of constructors, that can be used to create or pattern-match values of the corresponding enumerated type.

Enumerations are declared with the keyword `enum`.

An example of an `enum` item and its use:

    #![allow(unused)]
    fn main() {
    enum Animal {
        Dog,
        Cat,
    }

    let mut a: Animal = Animal::Dog;
    a = Animal::Cat;
    }

Enum constructors can have either named or unnamed fields:

    #![allow(unused)]
    fn main() {
    enum Animal {
        Dog(String, f64),
        Cat { name: String, weight: f64 },
    }

    let mut a: Animal = Animal::Dog("Cocoa".to_string(), 37.2);
    a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };
    }

In this example, `Cat` is a struct-like enum variant, whereas `Dog` is simply called an enum variant. Each enum instance has a discriminant which is an integer associated to it that is used to determine which variant it holds. An opaque reference to this discriminant can be obtained with the `mem::discriminant` function.

## Custom Discriminant Values for Fieldless Enumerations

If there is no data attached to any of the variants of an enumeration, then the discriminant can be directly chosen and accessed.

These enumerations can be cast to integer types with the `as` operator by a numeric cast. The enumeration can optionally specify which integer each discriminant gets by following the variant name with `=` followed by a constant expression. If the first variant in the declaration is unspecified, then it is set to zero. For every other unspecified discriminant, it is set to one higher than the previous variant in the declaration.

    #![allow(unused)]
    fn main() {
    enum Foo {
        Bar,            // 0
        Baz = 123,      // 123
        Quux,           // 124
    }

    let baz_discriminant = Foo::Baz as u32;
    assert_eq!(baz_discriminant, 123);
    }

Under the default representation, the specified discriminant is interpreted as an `isize` value although the compiler is allowed to use a smaller type in the actual memory layout. The size and thus acceptable values can be changed by using a primitive representation or the `C` representation.

It is an error when two variants share the same discriminant.

    #![allow(unused)]
    fn main() {
    enum SharedDiscriminantError {
        SharedA = 1,
        SharedB = 1
    }

    enum SharedDiscriminantError2 {
        Zero,       // 0
        One,        // 1
        OneToo = 1  // 1 (collision with previous!)
    }
    }

It is also an error to have an unspecified discriminant where the previous discriminant is the maximum value for the size of the discriminant.

    #![allow(unused)]
    fn main() {
    #[repr(u8)]
    enum OverflowingDiscriminantError {
        Max = 255,
        MaxPlusOne // Would be 256, but that overflows the enum.
    }

    #[repr(u8)]
    enum OverflowingDiscriminantError2 {
        MaxMinusOne = 254, // 254
        Max,               // 255
        MaxPlusOne         // Would be 256, but that overflows the enum.
    }
    }

## Zero-variant Enums

Enums with zero variants are known as zero-variant enums. As they have no valid values, they cannot be instantiated.

    #![allow(unused)]
    fn main() {
    enum ZeroVariants {}
    }

Zero-variant enums are equivalent to the never type, but they cannot be coerced into other types.

    #![allow(unused)]
    fn main() {
    enum ZeroVariants {}
    let x: ZeroVariants = panic!();
    let y: u32 = x; // mismatched type error
    }

## Variant visibility

Enum variants syntactically allow a Visibility annotation, but this is rejected when the enum is validated. This allows items to be parsed with a unified syntax across different contexts where they are used.

    #![allow(unused)]
    fn main() {
    macro_rules! mac_variant {
        ($vis:vis $name:ident) => {
            enum $name {
                $vis Unit,

                $vis Tuple(u8, u16),

                $vis Struct { f: u8 },
            }
        }
    }

    // Empty `vis` is allowed.
    mac_variant! { E }

    // This is allowed, since it is removed before being validated.
    #[cfg(FALSE)]
    enum E {
        pub U,
        pub(crate) T(u8),
        pub(super) T { f: String }
    }
    }