Vòng lặp while trong Rust
Vòng lặp while cứ chạy mãi chừng nào điều kiện vẫn còn true. Đây là công cụ phù hợp khi bạn biết mình đang chờ điều gì, dù không biết chính xác sẽ phải lặp bao nhiêu lần.
Vòng lặp while cơ bản
Phần tiêu đề “Vòng lặp while cơ bản”fn main() { let mut count = 1;
while count <= 5 { println!("{count}"); count += 1; }}Kết quả:
12345Điều kiện (count <= 5) được kiểm tra trước mỗi lần chạy thân vòng lặp. Ngay khi nó thành false, vòng lặp kết thúc — ở đây là sau khi count thành 6.
while so với loop
Phần tiêu đề “while so với loop”Bạn có thể viết cùng một việc bằng loop kèm if/break tự viết tay, nhưng while nói thẳng ý bạn hơn: “cứ tiếp tục chừng nào điều này còn đúng.” Hãy để dành loop cho những trường hợp mà điều kiện dừng không nằm tự nhiên ở đầu vòng lặp.
// dùng while — rõ ràng, đi thẳng vào vấn đềlet mut n = 0;while n < 3 { println!("{n}"); n += 1;}
// cùng việc đó bằng loop — vẫn chạy, nhưng phải đọc nhiều hơnlet mut n = 0;loop { if n >= 3 { break; } println!("{n}"); n += 1;}Một ví dụ thực tế hơn
Phần tiêu đề “Một ví dụ thực tế hơn”while hay được dùng cho những việc như chờ một giá trị đạt tới mục tiêu:
fn main() { let mut balance = 100;
while balance < 200 { balance += 25; println!("Số dư hiện tại là {balance}"); }
println!("Đã đạt mục tiêu!");}Kết quả:
Số dư hiện tại là 125Số dư hiện tại là 150Số dư hiện tại là 175Số dư hiện tại là 200Đã đạt mục tiêu!Điều kiện có thể là bất kỳ biểu thức nào cho ra một bool, nên bạn có thể kết hợp nhiều phép kiểm tra bằng && và || trong bài Toán tử, chẳng hạn while balance < 200 && months < 12.
Rust không có do-while
Phần tiêu đề “Rust không có do-while”Một số ngôn ngữ có vòng lặp do { ... } while (condition). Nó chạy thân vòng lặp trước rồi mới kiểm tra điều kiện, nên thân vòng lặp luôn chạy ít nhất một lần. Rust không có loại này. Thay vào đó, bạn dùng loop và đặt phép kiểm tra ở cuối.
Đây là một trường hợp mà điều đó quan trọng. Để đếm số chữ số của một số, bạn có thể chia liên tục cho 10 đến khi không còn gì. Nhưng số 0 vẫn có một chữ số, và một vòng lặp while thông thường không hề chạy với nó:
fn main() { let number = 0;
// Vòng lặp while kiểm tra trước, nên nó không bao giờ chạy với 0. let mut n = number; let mut digits = 0; while n > 0 { digits += 1; n /= 10; } println!("while bảo {number} có {digits} chữ số");
// loop + kiểm tra ở cuối thì thân vòng lặp chạy ít nhất một lần. let mut n = number; let mut digits = 0; loop { digits += 1; n /= 10; if n == 0 { break; } } println!("loop bảo {number} có {digits} chữ số");}Kết quả:
while bảo 0 có 0 chữ sốloop bảo 0 có 1 chữ sốĐổi number thành 4096 thì cả hai phiên bản đều đồng ý: 4 chữ số. Sự khác biệt chỉ lộ ra khi điều kiện sai ngay từ đầu. Vì vậy, quy tắc dễ nhớ là: nếu thân vòng lặp phải chạy ít nhất một lần, hãy viết loop với if ... { break; } ở cuối.
Còn một kiểu vòng lặp while nữa là while let, chạy chừng nào một giá trị còn khớp với một mẫu (pattern). Nó được giới thiệu trong bài If Let và While Let.
Luyện tập
Phần tiêu đề “Luyện tập”1. Cộng dồn đến khi vượt 100
Phần tiêu đề “1. Cộng dồn đến khi vượt 100”Cộng dồn 1 + 2 + 3 + … và dừng ngay khi tổng lớn hơn 100. In ra bạn đã cộng bao nhiêu số và tổng là bao nhiêu. Gợi ý: bạn cần hai biến mut, một cho số tiếp theo và một cho tổng.
Xem lời giải
fn main() { let mut next = 1; let mut total = 0;
while total <= 100 { total += next; next += 1; }
println!("Đã cộng {} số, tổng là {total}", next - 1);}Kết quả:
Đã cộng 14 số, tổng là 105Sau lượt cuối, next đã tiến thêm một bước, vì thế ta in next - 1. Những chi tiết lệch một đơn vị (off-by-one) như thế này rất đáng để bạn thử nhẩm lại với một ví dụ nhỏ.
2. Chia đôi đến khi còn 1
Phần tiêu đề “2. Chia đôi đến khi còn 1”Bắt đầu với 1000. Chừng nào số đó còn lớn hơn 1, hãy chia nó cho 2 (chia nguyên) và in ra. Cuối cùng, in ra đã cần bao nhiêu lần chia đôi. Gợi ý: n /= 2 chia n cho 2 và bỏ phần dư.
Xem lời giải
fn main() { let mut n = 1000; let mut steps = 0;
while n > 1 { n /= 2; steps += 1; println!("{n}"); }
println!("Cần {steps} lần chia đôi để về 1");}Kết quả:
500250125623115731Cần 9 lần chia đôi để về 1125 / 2 là 62 chứ không phải 62.5, vì cả hai số đều là số nguyên. Nhờ vậy vòng lặp dừng đúng ở 1.
Tóm tắt
Phần tiêu đề “Tóm tắt”while condition { ... }lặp lại chừng nào điều kiện còntrue, và điều kiện được kiểm tra trước mỗi lần chạy.- Hãy chắc rằng có thứ gì đó bên trong vòng lặp cuối cùng sẽ làm điều kiện thành
false, nếu không nó sẽ chạy mãi mãi. - Ưu tiên
whilethay choloopkhi điều kiện dừng có thể diễn đạt tự nhiên là “chừng nào X còn đúng”. - Rust không có do-while. Khi thân vòng lặp phải chạy ít nhất một lần, hãy dùng
loopvới phép kiểm trabreakở cuối.
Kiểm tra nhanh
Phần tiêu đề “Kiểm tra nhanh”Kiểm tra nhanh
1. Lỗi kinh điển nào gây ra một vòng lặp while vô hạn?
2. Theo bài này, khi nào nên ưu tiên while thay cho loop?
3. Làm sao để viết một vòng lặp mà thân của nó luôn chạy ít nhất một lần?
Điểm: 0 / 3
Đọc thêm
Phần tiêu đề “Đọc thêm”- Conditional Loops with while — The Rust Book (tiếng Anh): phần giới thiệu chính thức, so sánh
whilevớiloop. - while — Rust by Example (tiếng Anh): một chương trình FizzBuzz chạy được, viết bằng vòng lặp
while. - Predicate loops — The Rust Reference (tiếng Anh): các quy tắc chính xác về cách một vòng lặp
whilechạy. - Từ khóa
while— tài liệu thư viện chuẩn (tiếng Anh): tóm tắt ngắn vềwhilevàwhile let, kèm ví dụ.