Vòng lặp với khớp mẫu trong Rust: loop và while let
Làm chủ vòng lặp với khớp mẫu trong Rust: trả về giá trị từ loop, giải nén dữ liệu với while let, và kiểm soát luồng lồng nhau bằng loop label.
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 for và while 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:
- Máy bán hàng tự động (
loopvớibreak 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). - 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:
fn retry_operation() -> i32 {
let mut attempts = 0;
let result = loop {
attempts += 1;
if attempts == 3 {
// Trả về giá trị 42 từ biểu thức loop gán thẳng vào biến 'result'
break attempts * 14;
}
};
result
}
fn main() {
let output = retry_operation();
println!("Kết quả: {output}"); // 42
}rustgraph 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)#
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
}
}rustCách viết chuẩn mực với while let#
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 letmỗi khi cần tiêu thụ (drain) dữ liệu từOptionhoặcResult, 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 break và continue 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:
fn main() {
let mut count = 0;
'counting_up: loop {
println!("count = {count}");
let mut remaining = 10;
loop {
println!("remaining = {remaining}");
if remaining == 9 {
break; // Chỉ thoát khỏi vòng lặp bên trong
}
if count == 2 {
break 'counting_up; // Thoát hẳn khỏi vòng lặp ngoài cùng
}
remaining -= 1;
}
count += 1;
}
println!("End count = {count}");
}rustsequenceDiagram
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úc | Trường hợp sử dụng chính | Hỗ trợ break value? | Khớp mẫu tự động? |
|---|---|---|---|
loop | Vòng lặp vô hạn, cơ chế retry, worker thread | Có | Tùy chọn với match bên trong |
while condition | Lặp dựa trên điều kiện boolean thông thường | Không | Không |
while let pattern | Tiêu thụ tập hợp chứa Option / Result | Không | Có (tự động bind biến) |
for item in iter | Duyệt qua danh sách, khoảng số đã biết | Không | Có (destructure phần tử) |
Tổng kết#
- Cú pháp
loopcó thể trả về giá trị sau khi dừng thông quabreak value. while letthay thế hoàn hảo cho khốiloop + matchdà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.