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)