0

7 idiom Rust giúp code sạch và hiệu năng cao

Rust nổi tiếng với compiler nghiêm khắc, dev mới thường cảm thấy bị borrow checker "trói tay trói chân". Nhưng Rustacean kinh nghiệm biết rằng dưới những quy tắc nghiêm ngặt đó ẩn chứa nhiều trick thông minh vừa idiomatic vừa performant. Những pattern này ban đầu hơi counterintuitive, nhưng hoàn toàn align với design philosophy của Rust và làm code sạch + nhanh hơn đáng kể.

image.png Dưới đây là 7 technique mang lại cả readability lẫn efficiency.


1. Explicitly drop Result/Option: "Tui biết tui đang làm gì"

Rust ép bạn handle ResultOption, nhưng đôi khi kết quả thật sự không quan trọng – như gửi metrics không critical hay dọn temp file. Ignore chúng sẽ bị warning unused_result làm rối IDE.

Fix: Dùng let _ = ... hoặc drop(...) để bảo compiler: "Tui hiểu, nhưng tui kệ".

use std::fs;

fn main() {
    // Thử xóa temp cache file – fail cũng kệ
    let _ = fs::remove_file("/tmp/temp_cache.dat"); 
    
    println!("Thử dọn cache, kết quả không quan trọng.");

    // Hold Option, rồi drop ngay để giải phóng resource
    let config_data: Option<String> = Some(String::from("Heavy Config Data"));
    drop(config_data); 
    
    // config_data giờ đã moved/dropped – truy cập sẽ lỗi compile
}

Cách này silence warning mà vẫn explicit intent.


2. if letwhile let: Làm phẳng control flow

match mạnh nhưng verbose khi chỉ care 1 case. Viết match với _ => {} thêm indent không cần thiết.

Dùng: if let cho single match, while let cho iterator/loop pattern.

fn main() {
    // Chỉ handle khi config tồn tại
    let app_mode: Option<&str> = Some("Production");

    if let Some(mode) = app_mode {
        println!("Chạy ở mode: {}", mode);
    }

    // Consume queue đến khi hết
    let mut tasks = vec!["Task A", "Task B", "Task C"].into_iter();

    while let Some(task) = tasks.next() {
        println!("Đang xử lý: {}", task);
    }
}

Giảm visual noise, highlight business logic rõ hơn.


3. VecDeque: Double-ended queue bị đánh giá thấp

Nhiều dev default dùng Vec cho mọi list. Nhưng với FIFO queue (pop front thường xuyên), Vec::remove(0) shift hết element sau – O(n) thảm họa

Giải pháp: VecDeque dùng ring buffer. Pop/push front/back đều amortized O(1).

use std::collections::VecDeque;

fn main() {
    let mut buffer = VecDeque::from(vec![100, 200, 300]);

    // Pop front – nhanh hơn Vec vài bậc với data lớn
    if let Some(val) = buffer.pop_front() {
        println!("Xử lý đầu queue: {}", val);
    }

    // Vẫn push back bình thường
    buffer.push_back(400);
}

Đổi VecVecDeque trong task scheduler hay message buffer là perf win ngay.


4. const vs static: Biết dùng cái nào

Newbie hay nhầm lẫn. Phân biệt rõ:

  • const: Compile-time constant. Inline everywhere (không có runtime address).
  • static: Global với fixed memory address (dùng với atomic cho shared state).
use std::sync::atomic::{AtomicUsize, Ordering};

// Compile-time constant – inline everywhere
const MAX_CONNECTIONS: u32 = 100; 

// Global counter với fixed address
static ACTIVE_USERS: AtomicUsize = AtomicUsize::new(0);

fn new_connection() {
    ACTIVE_USERS.fetch_add(1, Ordering::SeqCst);
    
    if ACTIVE_USERS.load(Ordering::SeqCst) as u32 <= MAX_CONNECTIONS {
        println!("Cho phép kết nối");
    }
}

const cho config/math, static cho true global.


5. PhantomData: Bóng ma của type system

PhantomData là zero-sized type, tồn tại chỉ để lừa compiler nghĩ struct "own" type/lifetime relationship nào đó – zero runtime cost. Hoàn hảo cho: State marker, FFI boundary, phantom ownership.

use std::marker::PhantomData;

// State marker (zero runtime size)
struct Connected;
struct Disconnected;

struct Client<T> {
    id: u32,
    _state: PhantomData<T>, 
}

impl<T> Client<T> {
    fn new(id: u32) -> Self {
        Client { id, _state: PhantomData }
    }
}

fn main() {
    let c1: Client<Connected> = Client::new(1);
    let c2: Client<Disconnected> = Client::new(2);

    // Compiler coi 2 cái này là type hoàn toàn khác
    println!("Client ID: {}", c1.id);
}

Enable zero-cost type safety và state machine.


6. Const Generics: Parameterize value ở compile time

Traditional generic parameterize type. Const generic parameterize value, cho phép stack-allocated fixed-size structure.

// Fixed-size matrix với compile-time dimension
struct Matrix<T, const ROWS: usize, const COLS: usize> {
    data: [[T; COLS]; ROWS],
}

impl<T: Default + Copy, const ROWS: usize, const COLS: usize> Matrix<T, ROWS, COLS> {
    fn new() -> Self {
        Matrix {
            data: [[T::default(); COLS]; ROWS],
        }
    }

    fn size_info(&self) {
        println!("Kích thước matrix: {}x{}", ROWS, COLS);
    }
}

fn main() {
    let mat = Matrix::<f64, 4, 4>::new();
    mat.size_info();
}

No heap alloc, perfect cho embedded/math-heavy code.


7. impl Trait return: Ẩn implementation detail

Return iterator chain phức tạp kiểu Map<Filter<Range<...>>> vừa viết đau vừa brittle. Internal change là API break.

Giải pháp: -> impl Trait – "Return thứ gì đó implement trait này, tin tui đi".

// Caller không cần biết nó là filtered Range cụ thể
fn get_odd_numbers(limit: u32) -> impl Iterator<Item = u32> {
    (0..limit).filter(|x| x % 2 != 0)
}

fn main() {
    let odds = get_odd_numbers(10);
    
    // Chỉ iterate – hoàn toàn decoupled khỏi implementation
    for num in odds {
        println!("Số lẻ: {}", num);
    }
}

API stable và flexible hơn hẳn.


Rust tooling thiết yếu

Master code pattern chỉ là nửa trận chiến. Nửa còn lại là dev environment.

Rust dev tốn hàng giờ config toolchain, database dependency, PATH conflict. Skip hết với ServBay install rust environment with one click – không cần rustup lằng nhằng, không config tay.

Nó còn bundle SQL/NoSQL database (PostgreSQL, Redis) và reverse proxy, plus local AI deployment. Perfect cho full-stack prototype hay AI-assisted Rust dev – focus 100% vào logic và optimization.


Rust way

Những idiom này tìm sweet spot giữa safety và control của Rust. Khi bạn dùng PhantomData handle type constraint, VecDeque optimize queue perf, sẽ hiểu tại sao Rust xứng đáng là một trong những systems language mạnh nhất.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí