Structs, Enums and Pattern Matching in Rust
Rust's enums are far more powerful than enums in most languages: each variant can hold its own data. Combined with match, they let you model states so that invalid ones can't exist.
Structs and impl
#[derive(Debug, Clone)]
struct User {
id: u64,
name: String,
email: Option<String>,
}
impl User {
fn new(id: u64, name: &str) -> Self {
Self { id, name: name.to_string(), email: None }
}
fn display_name(&self) -> &str {
&self.name
}
}
Enums with data
enum PaymentStatus {
Pending,
Paid { transaction_id: String, amount: u64 },
Failed(String), // reason
Refunded { amount: u64 },
}
match must cover every case
fn describe(status: &PaymentStatus) -> String {
match status {
PaymentStatus::Pending => "Waiting for payment".to_string(),
PaymentStatus::Paid { amount, .. } => format!("Paid ₹{}", amount / 100),
PaymentStatus::Failed(reason) => format!("Failed: {reason}"),
PaymentStatus::Refunded { amount } if *amount == 0 => "Nothing refunded".into(),
PaymentStatus::Refunded { amount } => format!("Refunded ₹{}", amount / 100),
}
}
If you add a new variant later, every match that doesn't handle it stops compiling. That's how Rust keeps big codebases consistent.
if let and let else
// When you only care about one case
if let Some(email) = &user.email {
send_welcome(email);
}
// Unwrap or return early
fn domain(user: &User) -> Option<&str> {
let Some(email) = &user.email else {
return None;
};
email.split('@').nth(1)
}
Patterns everywhere
let (x, y) = (3, 4); // destructure a tuple
let User { name, .. } = user.clone(); // destructure a struct
match code { 200..=299 => "ok", 404 => "missing", _ => "error" };
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.