Question
In Rust, I can define enum variants that carry data like this:
enum MyEnum {
A(i32),
B(i32),
}
However, I cannot define an enum like this:
enum MyEnum {
A(123),
B(456),
}
Here, 123 and 456 are intended to be constant values for each variant.
Is there a simpler Rust pattern for representing enum variants with fixed constant values, without creating separate structs for each variant and implementing the values manually?
Short Answer
By the end of this page, you will understand why Rust does not allow enum variants like A(123) and B(456), and what to use instead. You will learn the difference between enum payloads and enum discriminants, how to attach fixed meanings to variants, and several practical Rust patterns for working with constant values in enums.
Concept
Rust enums can represent one of several possible variants. Each variant can optionally carry data.
For example:
enum MyEnum {
A(i32),
B(i32),
}
This does not mean that A always contains one specific number. It means:
Acan store anyi32valueBcan store anyi32value
So values like these are valid:
let x = MyEnum::A(123);
let y = MyEnum::A(999);
let z = MyEnum::B(456);
When you write A(i32), you are declaring the type of data that the variant can hold, not a fixed constant.
Mental Model
Think of an enum like a set of labeled cards.
A(i32)means: theAcard has a pocket that can hold anyi32Aby itself means: theAcard is just a label
If you want each label to stand for a fixed number, do not try to put the number inside the type definition as a literal. Instead, keep the labels simple and use a lookup rule:
Amaps to123Bmaps to456
So the enum is the name, and a method or match is the legend that tells you what each name means.
Syntax and Examples
1. Enum with associated data
Use this when each instance may carry a different value:
enum MyEnum {
A(i32),
B(i32),
}
fn main() {
let x = MyEnum::A(123);
let y = MyEnum::B(456);
}
Here, 123 and 456 are runtime values stored inside the enum variants.
2. Enum with fixed meanings
Use plain variants and map them to constants:
enum MyEnum {
A,
B,
}
impl MyEnum {
fn value(self) -> i32 {
match self {
MyEnum::A => 123,
MyEnum::B => 456,
}
}
}
fn () {
= MyEnum::A;
(, a.());
}
Step by Step Execution
Consider this example:
enum MyEnum {
A,
B,
}
impl MyEnum {
fn value(self) -> i32 {
match self {
MyEnum::A => 123,
MyEnum::B => 456,
}
}
}
fn main() {
let item = MyEnum::B;
let number = item.value();
println!("{}", number);
}
Step-by-step
-
enum MyEnum { A, B }- Defines two possible variants.
- Neither variant stores extra data.
-
impl MyEnum { fn value(self) -> i32 { ... } }- Adds a method named
value. - The method returns an
i32based on the variant.
- Adds a method named
-
let item = MyEnum::B;
Real World Use Cases
Status and code mappings
Enums often represent named states that correspond to fixed codes:
enum HttpStatusKind {
Ok,
NotFound,
ServerError,
}
impl HttpStatusKind {
fn code(self) -> u16 {
match self {
HttpStatusKind::Ok => 200,
HttpStatusKind::NotFound => 404,
HttpStatusKind::ServerError => 500,
}
}
}
Protocol or message types
A network protocol may use symbolic names in code but fixed numeric values on the wire.
enum MessageType {
Connect,
Disconnect,
}
impl MessageType {
fn id(self) -> u8 {
match self {
MessageType::Connect => 1,
MessageType::Disconnect => 2,
}
}
}
Configuration modes
An app might use variants for readable logic and methods for fixed settings.
Real Codebase Usage
In real Rust projects, developers usually choose one of these patterns depending on intent.
1. Fieldless enum + method
This is the most common when you want readable variants and fixed derived values.
enum LogLevel {
Debug,
Info,
Error,
}
impl LogLevel {
fn priority(self) -> u8 {
match self {
LogLevel::Debug => 10,
LogLevel::Info => 20,
LogLevel::Error => 30,
}
}
}
Why it is common:
- easy to read
- easy to extend
- works well with
match - avoids scattered magic numbers
2. Validation and conversion methods
Enums often expose helper methods like as_code, to_id, or from_code.
enum Role {
Admin,
User,
}
impl {
() {
{
Role::Admin => ,
Role::User => ,
}
}
(code: ) <> {
code {
=> (Role::Admin),
=> (Role::User),
_ => ,
}
}
}
Common Mistakes
Mistake 1: Treating tuple variant fields as fixed values
Broken code:
enum MyEnum {
A(123),
B(456),
}
Why it fails:
- Rust expects a type like
i32, not a literal like123.
Fix:
enum MyEnum {
A,
B,
}
impl MyEnum {
fn value(self) -> i32 {
match self {
MyEnum::A => 123,
MyEnum::B => 456,
}
}
}
Mistake 2: Using associated data when no variable data is needed
Less ideal:
enum MyEnum {
A(i32),
B(),
}
= MyEnum::();
Comparisons
| Pattern | Example | Best when | Notes |
|---|---|---|---|
| Enum with payload | A(i32) | each variant carries variable data | A(1) and A(999) are both valid |
| Fieldless enum + method | A, B + value() | each variant maps to a fixed meaning | most idiomatic for fixed per-variant values |
| Fieldless enum + discriminants | A = 123 | you need explicit numeric codes | useful for casting and interop |
| Associated constants | const A: i32 = 123 |
Cheat Sheet
// Variable data per variant
enum MyEnum {
A(i32),
B(i32),
}
// Fixed meaning per variant
enum MyEnum2 {
A,
B,
}
impl MyEnum2 {
fn value(self) -> i32 {
match self {
MyEnum2::A => 123,
MyEnum2::B => 456,
}
}
}
// Explicit discriminants for fieldless enums
enum MyEnum3 {
A = 123,
B = 456,
}
Rules to remember
A(i32)meansAcarries a value of typei32A(123)is invalid in an enum definition because123is a value, not a type- Use
A = 123only for fieldless enums - Use a method like
value()when variants should map to fixed constants
FAQ
Can I write A(123) directly inside a Rust enum definition?
No. Inside A(...) in an enum definition, Rust expects a type, not a literal value.
How do I give each enum variant a fixed integer in Rust?
Use a fieldless enum with explicit discriminants:
enum MyEnum {
A = 123,
B = 456,
}
Or use a method that returns the desired value.
What is the difference between A(i32) and A = 123?
A(i32)means the variant stores ani32A = 123means the variant has discriminant value123
These are different concepts.
When should I use a method instead of discriminants?
Use a method when you want a readable mapping, extra flexibility, or values that may later depend on more logic.
Are enum discriminants only for fieldless enums?
Yes, explicit discriminants are used with fieldless enums in the normal C-like style.
Is using constants instead of enums okay?
Yes, if you only need named values. But if the values represent a closed set of choices, enums are usually safer and clearer.
Mini Project
Description
Build a small Rust program that models command types for a fictional device. Each command should be represented as an enum variant, and each variant should map to a fixed numeric code. This demonstrates the common Rust pattern of using a fieldless enum with a method instead of trying to put literal values inside tuple-like enum variant definitions.
Goal
Create an enum whose variants represent device commands and provide a method that returns the fixed numeric code for each command.
Requirements
- Define a fieldless enum named
Commandwith at least three variants. - Add a method that returns a numeric code for each variant.
- In
main, create a few enum values and print their codes. - Use
matchto map variants to constants. - Keep the program valid and runnable as a single Rust file.
Keep learning
Related questions
Accessing Cargo Package Metadata in Rust
Learn how to read Cargo package metadata like version, name, and authors in Rust using compile-time environment macros.
Associated Types vs Generic Type Parameters in Rust: When to Use Each
Learn when to use associated types vs generic parameters in Rust traits, with clear rules, examples, and practical API design advice.
Can a Struct Extend Another Struct in Rust? Composition vs Inheritance
Learn how Rust handles struct reuse without inheritance, using composition, traits, and wrapper structs with practical examples.