π Rust Enums
Enums allow you to define a type by enumerating its possible variants.
π¦ Basic Enum
β Use It
π Enum with Data
Variants can hold data (like structs or tuples).
β Use It
π§ Match on Enum
match msg1 {
Message::Write(text) => println!("Message: {}", text),
Message::Move { x, y } => println!("Move to ({}, {})", x, y),
Message::Quit => println!("Quit!"),
Message::ChangeColor(r, g, b) => println!("Color: {}, {}, {}", r, g, b),
}
π Enum with Methods
impl Message {
fn call(&self) {
match self {
Message::Quit => println!("Quit"),
Message::Move { x, y } => println!("Move to ({}, {})", x, y),
Message::Write(text) => println!("Write: {}", text),
Message::ChangeColor(r, g, b) => println!("Color: {}, {}, {}", r, g, b),
}
}
}
πͺ Enums with Option
& Result
Rustβs standard library uses enums heavily:
let maybe_num: Option<i32> = Some(5);
let none_num: Option<i32> = None;
let result: Result<i32, &str> = Ok(10);
let error: Result<i32, &str> = Err("Oops");
π§ͺ Matching on Option
π Matching on Result
π Derive Debug
π₯ if-let
Syntax
let config_max = Some(3u8);
match config_max {
Some(max) => println!("The maximum is configured to be {max}"),
_ => (),
}
can be simplified with if let
:
let config_max = Some(3u8);
if let Some(max) = config_max {
println!("The maximum is configured to be {max}");
}
ππ» let-else
Syntax
- original code:
fn describe_state_quarter(coin: Coin) -> Option<String> {
let state = if let Coin::Quarter(state) = coin {
state
} else {
return None;
};
if state.existed_in(1900) {
Some(format!("{state:?} is pretty old, for America!"))
} else {
Some(format!("{state:?} is relatively new."))
}
}
- can be simplified with
let-else
:
fn describe_state_quarter(coin: Coin) -> Option<String> {
let Coin::Quarter(state) = coin else {
return None;
};
if state.existed_in(1900) {
Some(format!("{state:?} is pretty old, for America!"))
} else {
Some(format!("{state:?} is relatively new."))
}
}
β The ?
Operator in Rust
The ?
operator is used to propagate errors in functions that return a Result
or Option
.
β
For Result
fn read_file() -> Result<String, std::io::Error> {
let content = std::fs::read_to_string("file.txt")?; // if error, returns it early
Ok(content)
}
- If
read_to_string
returnsOk(val)
,val
is assigned. - If it returns
Err(e)
, the whole function returnsErr(e)
early.
Equivalent to:
β
For Option
fn get_first_char(s: &str) -> Option<char> {
let first = s.chars().next()?; // If None, return None early
Some(first)
}
β Requirements
- The function must return a
Result<_, E>
orOption<_>
. - The error type must implement
From
trait (auto for most common errors). - You can only use
?
inside functions that return compatible types.
π§ Good For:
- Cleaner error handling.
- Early returns on error without boilerplate.
TL;DR
Use Case | Behavior |
---|---|
Result |
Return Err(e) early if error |
Option |
Return None early if None |
Use ?
to write cleaner, less nested code when dealing with fallible operations.