blog.dopana

Back

Rust biến các vòng lặp trở thành những cấu trúc kiểm soát luồng vô cùng biểu cảm và mạnh mẽ. Ngoài các vòng lặp forwhile thông thường, Rust cung cấp biểu thức loop có khả năng trả về giá trị, while let để duyệt dữ liệu dạng khớp mẫu, và nhãn vòng lặp (loop label) giúp điều khiển các tầng vòng lặp lồng nhau.

Explain Like I’m 10: Máy Bán Hàng & Hộp Kẹo Lò Xo#

Hãy hình dung hai cơ chế sau:

  1. Máy bán hàng tự động (loop với break giá_trị): Bạn liên tục bỏ thêm xu vào máy cho đến khi trúng thưởng; khi đạt điều kiện, máy nhả thẳng phần thưởng vào tay bạn (break quà_tặng).
  2. Hộp kẹo lò xo Pez (while let Some(kẹo)): Mỗi lần bạn bật nắp hộp kẹo, bạn kiểm tra xem có kẹo trồi lên không. Chừng nào vẫn còn kẹo (Some(kẹo)), bạn ăn viên kẹo đó. Ngay khi hộp kẹo hết sạch (None), bạn đóng nắp và dừng lại một cách tự nhiên.
graph TD
    Start["Bắt đầu vòng lặp"] --> PatternMatch{"Biểu thức có khớp mẫu không?<br/>(Ví dụ: Some(item))"}
    PatternMatch -->|Có: Giải nén item| LoopBody["Thực thi thân vòng lặp với item"]
    LoopBody --> NextEval["Đánh giá phần tử / trạng thái tiếp theo"]
    NextEval --> PatternMatch
    PatternMatch -->|Không: None / Không khớp| Terminate["Thoát vòng lặp an toàn"]

Biểu Thức loop: Trả Về Giá Trị Khi Thoát#

Không giống như nhiều ngôn ngữ họ C nơi vòng lặp chỉ là câu lệnh đơn thuần (statement), trong Rust, loop là một biểu thức (expression). Bạn có thể truyền một giá trị phía sau break để trả về giá trị đó từ vòng lặp:

graph LR
    LStart["Bắt đầu loop"] --> Work["Thực hiện lượt thử"]
    Work --> Check{"Đạt điều kiện thành công?"}
    Check -->|Chưa| Work
    Check -->|Rồi: break value| ReturnVal["result = giá trị trả về"]

while let: Lặp Chừng Nào Mẫu Còn Khớp#

Khi cần rút từng phần tử từ ngăn xếp (stack), hàng đợi (queue), kênh truyền thông (channel) hoặc iterator, cú pháp thông thường đòi hỏi unwrap rất cồng kềnh. while let cho phép chạy thân vòng lặp liên tục chừng nào biểu thức còn khớp với mẫu định sẵn:

Cách viết dài dòng (Dùng loop + match)#

src/main.rs
let mut stack = vec![1, 2, 3];

loop {
    match stack.pop() {
        Some(top) => println!("Lấy ra: {top}"),
        None => break, // Thoát khi ngăn xếp rỗng
    }
}
rust

Cách viết chuẩn mực với while let#

src/main.rs
let mut stack = vec![1, 2, 3];

// Lặp liên tục chừng nào stack.pop() còn trả về Some(top)
while let Some(top) = stack.pop() {
    println!("Lấy ra: {top}");
}
rust

[!TIP] Hãy tận dụng while let mỗi khi cần tiêu thụ (drain) dữ liệu từ Option hoặc Result, ví dụ như đọc dữ liệu liên tục từ message receiver (receiver.recv()) cho đến khi channel đóng.

Nhãn Vòng Lặp (Loop Labels): Điều Khiển Vòng Lặp Lồng Nhau#

Khi có nhiều vòng lặp lồng nhau, các lệnh breakcontinue mặc định chỉ áp dụng cho vòng lặp trong cùng. Bạn có thể gắn một nhãn vòng lặp (bắt đầu bằng dấu nháy đơn ') để thoát hoặc chuyển bước trực tiếp ở vòng lặp ngoài:

sequenceDiagram
    participant Outer as VongLapNgoai
    participant Inner as VongLapTrong
    
    Outer->>Inner: Tien vao vong lap trong
    Inner->>Inner: remaining == 9: break trong
    Inner-->>Outer: Tro lai vong lap ngoai
    Outer->>Inner: Tien vao vong lap trong khi count bang 2
    Inner->>Outer: break counting_up: Nhay thoat khoi vong lap ngoai

Bảng So Sánh Các Kiểu Vòng Lặp Trong Rust#

Cấu trúcTrường hợp sử dụng chínhHỗ trợ break value?Khớp mẫu tự động?
loopVòng lặp vô hạn, cơ chế retry, worker threadTùy chọn với match bên trong
while conditionLặp dựa trên điều kiện boolean thông thườngKhôngKhông
while let patternTiêu thụ tập hợp chứa Option / ResultKhôngCó (tự động bind biến)
for item in iterDuyệt qua danh sách, khoảng số đã biếtKhôngCó (destructure phần tử)

Tổng kết#

  • Cú pháp loop có thể trả về giá trị sau khi dừng thông qua break value.
  • while let thay thế hoàn hảo cho khối loop + match dài dòng khi duyệt rút dữ liệu từ tập hợp.
  • Gắn nhãn vòng lặp ('nhan: loop) cho phép điều hướng chính xác giữa các tầng vòng lặp lồng nhau.

Tài liệu tham khảo#