DEV Community

Subesh Yadav
Subesh Yadav

Posted on

🦀 Day 7 of #100DaysOfRust: Exploring Enums, Variants, and Option<T> in Rust

Today was all about understanding enums, how they differ from structs, how they model real-world data better in some cases, and why Option is Rust’s safe alternative to null.

📚 What Are Enums?

While structs let you group multiple pieces of data, enums let you express a value that could be one of many types.

Think of enums as a way to say: "This value is either this, that, or something else."

enum IpAddrKind {
    V4,
    V6,
}
Enter fullscreen mode Exit fullscreen mode

With this, you can create variables like:

let home = IpAddrKind::V4;
let loopback = IpAddrKind::V6;
Enter fullscreen mode Exit fullscreen mode

All values created with the enum are of the same type (IpAddrKind), even though they hold different "meanings".

đź§­ Enums vs Structs

You can achieve the same goal using structs and enums. For example:

struct IpAddr {
    kind: IpAddrKind,
    address: String,
}
Enter fullscreen mode Exit fullscreen mode

But with enums, you can directly associate data with each variant:

enum IpAddr {
    V4(String),
    V6(String),
}
Enter fullscreen mode Exit fullscreen mode

Or even mix types:

enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}
Enter fullscreen mode Exit fullscreen mode

This keeps your data structure concise and flexible.

đź§° Enums with Data

Rust enums are powerful because variants can:

  • Contain different types of data.
  • Contain different amounts of data.

Example:

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}
Enter fullscreen mode Exit fullscreen mode

Here:

  • Quit is like a unit struct (no data),
  • Move acts like a named struct,
  • Write is a tuple struct with one value,
  • ChangeColor is a tuple struct with three values.

You could also use four separate structs—but then you’d have to write separate logic for each. With enums, you get one unified type.

đź§  Defining Methods on Enums

Just like structs, you can define methods on enums using impl.

impl Message {
    fn call(&self) {
        println!("Called: {:?}", self);
    }
}
Enter fullscreen mode Exit fullscreen mode

And use it like:

let m = Message::Write(String::from("hello"));
m.call();
Enter fullscreen mode Exit fullscreen mode

🔎 The Option Enum

Rust doesn’t have null. Instead, it has the Option enum:

enum Option<T> {
    Some(T),
    None,
}
Enter fullscreen mode Exit fullscreen mode

This is Rust’s way of saying: "The value might be something or nothing."

Examples:

let some_number = Some(5);          // Option<i32>
let some_char = Some('e');          // Option<char>
let absent_number: Option<i32> = None;
Enter fullscreen mode Exit fullscreen mode

This avoids a billion-dollar problem of null values that plague other languages.

đźš« Option Prevents Dangerous Assumptions

Rust won’t let you do this:

let x: i8 = 5;
let y: Option<i8> = Some(5);
let sum = x + y; // ❌ ERROR
Enter fullscreen mode Exit fullscreen mode

Why? Because Option and i8 are different types. You must explicitly handle the case when a value might be None.

This forces you to safely unwrap or pattern match:

let y: Option<i8> = Some(5);

match y {
    Some(n) => println!("Got: {}", n),
    None => println!("No value!"),
}
Enter fullscreen mode Exit fullscreen mode

🆚 Option vs Null (Why It’s Better)

  • Null is unchecked: you often forget to handle it, leading to runtime crashes.
  • Option is checked: the compiler forces you to handle the None case.
  • With Option, you’re explicit about the possibility of absence.
  • This makes your code more reliable, less error-prone, and easier to reason about.

đź§© Enums in the Standard Library

The Rust standard library contains many useful enums, like:

enum Result<T, E> {
    Ok(T),
    Err(E),
}

Or the IpAddr type:

enum IpAddr {
    V4(Ipv4Addr),
    V6(Ipv6Addr),
}
Enter fullscreen mode Exit fullscreen mode

You can use any data in enums: primitives, structs, or even other enums!

✍️ Summary

Here’s what I covered on Day 7:

  • Enums allow expressing one of many possible states or variants.
  • You can attach data of varying types to enum variants.
  • Enums are more appropriate than structs in many cases (like IpAddr).
  • You can define methods on enums using impl, just like structs.
  • Rust replaces unsafe null values with the safe and expressive Option.
  • Compiler forces you to handle the absence of values properly.
  • Option and pattern matching are key to writing robust Rust code.

Rust’s enums feel like algebraic data types from functional programming—powerful, precise, and safe. This was a big shift in thinking from JavaScript-style nullables, and I’m loving it.

Top comments (0)