Chuyển đến nội dung chính

Bài 4: Structs, Enums & Pattern Matching

Structs, impl blocks, methods. Enums, Option<T>, Result<T, E>. Pattern matching với match, if let, while let. Destructuring. Builder pattern.

💻 Lập trình — Bài 4 Bài 4: Structs, Enums & Pattern Matching

Rust: Từ Cơ bản đến Nâng cao

Phần 1: Rust Fundamentals

xdev.asia

1. Structs & Methods

#[derive(Debug, Clone)]
struct User {
    id: u64,
    username: String,
    email: String,
    active: bool,
}

impl User {
    // Associated function (constructor)
    fn new(id: u64, username: String, email: String) -> Self {
        Self {
            id,
            username,
            email,
            active: true,
        }
    }

    // Method — takes &self
    fn full_info(&self) -> String {
        format!("{} <{}>", self.username, self.email)
    }

    // Mutable method
    fn deactivate(&mut self) {
        self.active = false;
    }

    // Takes ownership
    fn into_username(self) -> String {
        self.username
    }
}

// Struct update syntax
let user2 = User {
    email: String::from("[email protected]"),
    ..user1
};

// Tuple struct
struct Color(u8, u8, u8);
struct Point(f64, f64);

2. Enums

#[derive(Debug)]
enum Shape {
    Circle(f64),                    // radius
    Rectangle { width: f64, height: f64 },
    Triangle(f64, f64, f64),        // 3 sides
}

impl Shape {
    fn area(&self) -> f64 {
        match self {
            Shape::Circle(r) => std::f64::consts::PI * r * r,
            Shape::Rectangle { width, height } => width * height,
            Shape::Triangle(a, b, c) => {
                let s = (a + b + c) / 2.0;
                (s * (s - a) * (s - b) * (s - c)).sqrt()
            }
        }
    }
}

// Option<T> — thay thế null
fn find_user(id: u64) -> Option<User> {
    if id == 1 {
        Some(User::new(1, "admin".into(), "[email protected]".into()))
    } else {
        None
    }
}

// Result<T, E> — error handling
fn parse_port(s: &str) -> Result<u16, String> {
    s.parse::<u16>().map_err(|e| format!("Invalid port: {}", e))
}

3. Pattern Matching nâng cao

// match guard
fn classify(x: i32) -> &'static str {
    match x {
        n if n < 0 => "negative",
        0 => "zero",
        n if n % 2 == 0 => "positive even",
        _ => "positive odd",
    }
}

// Destructuring nested
struct Order {
    id: u64,
    status: OrderStatus,
}

enum OrderStatus {
    Pending,
    Shipped { tracking: String },
    Delivered,
    Cancelled(String),
}

fn process_order(order: &Order) {
    match &order.status {
        OrderStatus::Shipped { tracking } => {
            println!("Order {} shipped: {}", order.id, tracking);
        }
        OrderStatus::Cancelled(reason) if reason.contains("fraud") => {
            println!("Fraud detected for order {}", order.id);
        }
        _ => {}
    }
}

4. Builder Pattern

#[derive(Debug)]
struct ServerConfig {
    host: String,
    port: u16,
    max_connections: usize,
    timeout_secs: u64,
}

struct ServerConfigBuilder {
    host: String,
    port: u16,
    max_connections: usize,
    timeout_secs: u64,
}

impl ServerConfigBuilder {
    fn new() -> Self {
        Self {
            host: "127.0.0.1".to_string(),
            port: 8080,
            max_connections: 100,
            timeout_secs: 30,
        }
    }

    fn host(mut self, host: &str) -> Self { self.host = host.to_string(); self }
    fn port(mut self, port: u16) -> Self { self.port = port; self }
    fn max_connections(mut self, max: usize) -> Self { self.max_connections = max; self }

    fn build(self) -> ServerConfig {
        ServerConfig {
            host: self.host,
            port: self.port,
            max_connections: self.max_connections,
            timeout_secs: self.timeout_secs,
        }
    }
}

// Sử dụng
let config = ServerConfigBuilder::new()
    .host("0.0.0.0")
    .port(3000)
    .max_connections(500)
    .build();

Bài tiếp theo: Traits & Generics.