Skip to main content
An enum variant in Rust is a distinct, mutually exclusive state or constructor defined within an enumeration (enum). Each variant represents a specific memory layout that the enum can assume at runtime, allowing a single enum type to encapsulate heterogeneous data structures under a unified type signature.

Variant Structures

Rust supports three structural forms of enum variants, which mirror the three types of structs available in the language. A single enum can contain any combination of these variant types:
  1. Unit Variants: Contain no associated data. They act as simple flags or identifiers.
  2. Tuple Variants: Contain anonymous, positional data fields. Types are specified, but fields are unnamed.
  3. Struct Variants: Contain named data fields, defined using curly braces.

Instantiation Syntax

Variants are instantiated using the namespace of the parent enum, followed by the path separator (::), and the specific variant constructor.

Data Extraction via Pattern Matching

Because the active variant of an enum is only known at runtime, accessing the data stored inside tuple and struct variants requires pattern matching. This is accomplished using match expressions or if let bindings, which destructure the variant and bind its inner data to local variables. To prevent consuming the enum instance and causing a borrow checker error, pattern matching is frequently performed on a reference to the enum.

Discriminants

Under the hood, Rust differentiates between variants at runtime using a hidden integer tag known as a discriminant. For enums consisting exclusively of unit variants (C-like enums), you can explicitly assign integer values to the discriminants. If unassigned, Rust implicitly assigns discriminants starting at 0.
Explicit discriminants can also be assigned to enums containing tuple or struct variants. This requires the enum to have an explicit primitive representation attribute (e.g., #[repr(u8)]) to define the exact size and type of the discriminant in memory.

Memory Layout

Because an enum instance can only hold one variant at a time, the memory footprint of an enum is statically determined at compile time by the largest variant it contains. The total size of the enum is calculated as: Size of the largest variant + Size of the discriminant + Alignment padding
Rust’s compiler may optimize the discriminant away entirely in certain scenarios (known as niche optimization). For example, in Option<&T>, the None variant is represented by a null pointer, resulting in zero memory overhead for the enum wrapper.
Tired of Poor Rust Skills? Fix That With Deep Grasping!Learn More