| r[items.enum] |
| # Enumerations |
| |
| r[items.enum.syntax] |
| ```grammar,items |
| Enumeration -> |
| `enum` IDENTIFIER GenericParams? WhereClause? `{` EnumVariants? `}` |
| |
| EnumVariants -> EnumVariant ( `,` EnumVariant )* `,`? |
| |
| EnumVariant -> |
| OuterAttribute* Visibility? |
| IDENTIFIER ( EnumVariantTuple | EnumVariantStruct )? EnumVariantDiscriminant? |
| |
| EnumVariantTuple -> `(` TupleFields? `)` |
| |
| EnumVariantStruct -> `{` StructFields? `}` |
| |
| EnumVariantDiscriminant -> `=` Expression |
| ``` |
| |
| r[items.enum.intro] |
| An *enumeration*, also referred to as an *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. |
| |
| r[items.enum.decl] |
| Enumerations are declared with the keyword `enum`. |
| |
| r[items.enum.namespace] |
| The `enum` declaration defines the enumeration type in the [type namespace] of the module or block where it is located. |
| |
| An example of an `enum` item and its use: |
| |
| ```rust |
| enum Animal { |
| Dog, |
| Cat, |
| } |
| |
| let mut a: Animal = Animal::Dog; |
| a = Animal::Cat; |
| ``` |
| |
| r[items.enum.constructor] |
| Enum constructors can have either named or unnamed fields: |
| |
| ```rust |
| 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. |
| |
| r[items.enum.fieldless] |
| An enum where no constructors contain fields is called a *<span id="field-less-enum">field-less enum</span>*. For example, this is a fieldless enum: |
| |
| ```rust |
| enum Fieldless { |
| Tuple(), |
| Struct{}, |
| Unit, |
| } |
| ``` |
| |
| r[items.enum.unit-only] |
| If a field-less enum only contains unit variants, the enum is called an *<span id="unit-only-enum">unit-only enum</span>*. For example: |
| |
| ```rust |
| enum Enum { |
| Foo = 3, |
| Bar = 2, |
| Baz = 1, |
| } |
| ``` |
| |
| r[items.enum.constructor-names] |
| Variant constructors are similar to [struct] definitions, and can be referenced by a path from the enumeration name, including in [use declarations]. |
| |
| r[items.enum.constructor-namespace] |
| Each variant defines its type in the [type namespace], though that type cannot be used as a type specifier. Tuple-like and unit-like variants also define a constructor in the [value namespace]. |
| |
| r[items.enum.struct-expr] |
| A struct-like variant can be instantiated with a [struct expression]. |
| |
| r[items.enum.tuple-expr] |
| A tuple-like variant can be instantiated with a [call expression] or a [struct expression]. |
| |
| r[items.enum.path-expr] |
| A unit-like variant can be instantiated with a [path expression] or a [struct expression]. For example: |
| |
| ```rust |
| enum Examples { |
| UnitLike, |
| TupleLike(i32), |
| StructLike { value: i32 }, |
| } |
| |
| use Examples::*; // Creates aliases to all variants. |
| let x = UnitLike; // Path expression of the const item. |
| let x = UnitLike {}; // Struct expression. |
| let y = TupleLike(123); // Call expression. |
| let y = TupleLike { 0: 123 }; // Struct expression using integer field names. |
| let z = StructLike { value: 123 }; // Struct expression. |
| ``` |
| |
| <span id="custom-discriminant-values-for-fieldless-enumerations"></span> |
| r[items.enum.discriminant] |
| ## Discriminants |
| |
| r[items.enum.discriminant.intro] |
| Each enum instance has a _discriminant_: an integer logically associated to it that is used to determine which variant it holds. |
| |
| r[items.enum.discriminant.repr-rust] |
| Under the [`Rust` representation], the discriminant is interpreted as an `isize` value. However, the compiler is allowed to use a smaller type (or another means of distinguishing variants) in its actual memory layout. |
| |
| ### Assigning discriminant values |
| |
| r[items.enum.discriminant.explicit] |
| #### Explicit discriminants |
| |
| r[items.enum.discriminant.explicit.intro] |
| In two circumstances, the discriminant of a variant may be explicitly set by following the variant name with `=` and a [constant expression]: |
| |
| r[items.enum.discriminant.explicit.unit-only] |
| 1. if the enumeration is "[unit-only]". |
| |
| r[items.enum.discriminant.explicit.primitive-repr] |
| 2. if a [primitive representation] is used. For example: |
| |
| ```rust |
| #[repr(u8)] |
| enum Enum { |
| Unit = 3, |
| Tuple(u16), |
| Struct { |
| a: u8, |
| b: u16, |
| } = 1, |
| } |
| ``` |
| |
| r[items.enum.discriminant.implicit] |
| #### Implicit discriminants |
| |
| If a discriminant for a variant is not specified, then it is set to one higher than the discriminant of the previous variant in the declaration. If the discriminant of the first variant in the declaration is unspecified, then it is set to zero. |
| |
| ```rust |
| enum Foo { |
| Bar, // 0 |
| Baz = 123, // 123 |
| Quux, // 124 |
| } |
| |
| let baz_discriminant = Foo::Baz as u32; |
| assert_eq!(baz_discriminant, 123); |
| ``` |
| |
| r[items.enum.discriminant.restrictions] |
| #### Restrictions |
| |
| r[items.enum.discriminant.restrictions.same-discriminant] |
| It is an error when two variants share the same discriminant. |
| |
| ```rust,compile_fail |
| enum SharedDiscriminantError { |
| SharedA = 1, |
| SharedB = 1 |
| } |
| |
| enum SharedDiscriminantError2 { |
| Zero, // 0 |
| One, // 1 |
| OneToo = 1 // 1 (collision with previous!) |
| } |
| ``` |
| |
| r[items.enum.discriminant.restrictions.above-max-discriminant] |
| It is also an error to have an unspecified discriminant where the previous discriminant is the maximum value for the size of the discriminant. |
| |
| ```rust,compile_fail |
| #[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. |
| } |
| ``` |
| |
| ### Accessing discriminant |
| |
| #### Via `mem::discriminant` |
| |
| r[items.enum.discriminant.access-opaque] |
| |
| [`std::mem::discriminant`] returns an opaque reference to the discriminant of an enum value which can be compared. This cannot be used to get the value of the discriminant. |
| |
| r[items.enum.discriminant.coercion] |
| #### Casting |
| |
| r[items.enum.discriminant.coercion.intro] |
| If an enumeration is [unit-only] (with no tuple and struct variants), then its discriminant can be directly accessed with a [numeric cast]; e.g.: |
| |
| ```rust |
| enum Enum { |
| Foo, |
| Bar, |
| Baz, |
| } |
| |
| assert_eq!(0, Enum::Foo as isize); |
| assert_eq!(1, Enum::Bar as isize); |
| assert_eq!(2, Enum::Baz as isize); |
| ``` |
| |
| r[items.enum.discriminant.coercion.fieldless] |
| [Field-less enums] can be cast if they do not have explicit discriminants, or where only unit variants are explicit. |
| |
| ```rust |
| enum Fieldless { |
| Tuple(), |
| Struct{}, |
| Unit, |
| } |
| |
| assert_eq!(0, Fieldless::Tuple() as isize); |
| assert_eq!(1, Fieldless::Struct{} as isize); |
| assert_eq!(2, Fieldless::Unit as isize); |
| |
| #[repr(u8)] |
| enum FieldlessWithDiscriminants { |
| First = 10, |
| Tuple(), |
| Second = 20, |
| Struct{}, |
| Unit, |
| } |
| |
| assert_eq!(10, FieldlessWithDiscriminants::First as u8); |
| assert_eq!(11, FieldlessWithDiscriminants::Tuple() as u8); |
| assert_eq!(20, FieldlessWithDiscriminants::Second as u8); |
| assert_eq!(21, FieldlessWithDiscriminants::Struct{} as u8); |
| assert_eq!(22, FieldlessWithDiscriminants::Unit as u8); |
| ``` |
| |
| #### Pointer casting |
| |
| r[items.enum.discriminant.access-memory] |
| |
| If the enumeration specifies a [primitive representation], then the discriminant may be reliably accessed via unsafe pointer casting: |
| |
| ```rust |
| #[repr(u8)] |
| enum Enum { |
| Unit, |
| Tuple(bool), |
| Struct{a: bool}, |
| } |
| |
| impl Enum { |
| fn discriminant(&self) -> u8 { |
| unsafe { *(self as *const Self as *const u8) } |
| } |
| } |
| |
| let unit_like = Enum::Unit; |
| let tuple_like = Enum::Tuple(true); |
| let struct_like = Enum::Struct{a: false}; |
| |
| assert_eq!(0, unit_like.discriminant()); |
| assert_eq!(1, tuple_like.discriminant()); |
| assert_eq!(2, struct_like.discriminant()); |
| ``` |
| |
| r[items.enum.empty] |
| ## Zero-variant enums |
| |
| r[items.enum.empty.intro] |
| Enums with zero variants are known as *zero-variant enums*. As they have no valid values, they cannot be instantiated. |
| |
| ```rust |
| enum ZeroVariants {} |
| ``` |
| |
| r[items.enum.empty.uninhabited] |
| Zero-variant enums are equivalent to the [never type], but they cannot be coerced into other types. |
| |
| ```rust,compile_fail |
| # enum ZeroVariants {} |
| let x: ZeroVariants = panic!(); |
| let y: u32 = x; // mismatched type error |
| ``` |
| |
| r[items.enum.variant-visibility] |
| ## 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. |
| |
| ```rust |
| 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 } |
| } |
| ``` |
| |
| [`C` representation]: ../type-layout.md#the-c-representation |
| [call expression]: ../expressions/call-expr.md |
| [constant expression]: ../const_eval.md#constant-expressions |
| [enumerated type]: ../types/enum.md |
| [Field-less enums]: #field-less-enum |
| [never type]: ../types/never.md |
| [numeric cast]: ../expressions/operator-expr.md#semantics |
| [path expression]: ../expressions/path-expr.md |
| [primitive representation]: ../type-layout.md#primitive-representations |
| [`Rust` representation]: ../type-layout.md#the-rust-representation |
| [struct expression]: ../expressions/struct-expr.md |
| [struct]: structs.md |
| [type namespace]: ../names/namespaces.md |
| [unit-only]: #unit-only-enum |
| [use declarations]: use-declarations.md |
| [value namespace]: ../names/namespaces.md |