Vòng lặp trong Rust
Rust có ba cách để lặp lại code: loop, while và for. Trang này nói về loop, cách đơn giản và trực tiếp nhất trong ba cách — nó lặp mãi mãi cho tới khi bạn bảo nó dừng.
Một vòng lặp cơ bản
Phần tiêu đề “Một vòng lặp cơ bản”fn main() { let mut count = 0;
loop { count += 1; println!("{count}");
if count == 3 { break; } }}Kết quả:
123Bản thân loop không bao giờ dừng — break mới là thứ kết thúc nó. Nếu không có if count == 3 { break; }, chương trình này sẽ in mãi mãi.
Trả về giá trị từ một vòng lặp
Phần tiêu đề “Trả về giá trị từ một vòng lặp”Đây là điều loop làm được mà while và for không làm được: bạn có thể đặt một giá trị sau break, và giá trị đó trở thành kết quả của cả vòng lặp:
fn main() { let mut count = 0;
let result = loop { count += 1; if count == 10 { break count * 2; // dừng lại và trả về một giá trị } };
println!("{result}");}Kết quả:
20Cách này tiện cho những việc kiểu “cứ thử lại cho tới khi thành công, rồi đưa tôi kết quả” — bạn sẽ gặp mẫu này trong code thực tế nhiều hơn bạn nghĩ.
Để ý dấu chấm phẩy sau dấu } đóng vòng lặp. Cả khối loop { ... } là vế phải của let result = ...;, nên câu lệnh let cần có ; ở cuối, giống như let x = 5;.
Vì sao dùng loop thay vì while true?
Phần tiêu đề “Vì sao dùng loop thay vì while true?”Nếu bạn đến từ ngôn ngữ khác, có thể bạn sẽ viết một vòng lặp vô tận là while true { ... }. Cách đó chạy được trong Rust, nhưng trình biên dịch sẽ cảnh báo bạn:
warning: denote infinite loops with `loop { ... }` --> src/main.rs:5:5 |5 | while true { | ^^^^^^^^^^ help: use `loop`Cảnh báo này khuyên bạn dùng loop { ... } để biểu thị vòng lặp vô tận. Đây không chỉ là chuyện phong cách. Rust biết rằng thân của một loop luôn luôn chạy, và cách duy nhất để thoát ra là một break. Nó không giả định như vậy với while true, vì nó không xét giá trị của điều kiện. Điều đó tạo ra khác biệt thật sự khi một biến nhận giá trị bên trong vòng lặp:
fn main() { let mut n = 1; let answer; // chưa có giá trị
loop { if n * n > 50 { answer = n * n; // gán ngay trước khi thoát ra break; } n += 1; }
println!("Số chính phương đầu tiên lớn hơn 50 là {answer}");}Kết quả:
Số chính phương đầu tiên lớn hơn 50 là 64Với loop, Rust thấy được rằng cách duy nhất để tới println! là đi qua break đó, nên answer luôn được gán giá trị. Đổi loop thành while true và bạn sẽ nhận lỗi error[E0381]: used binding answer is possibly-uninitialized (biến answer có thể chưa được khởi tạo). Trình biên dịch cho rằng vòng lặp có thể kết thúc mà không chạy if lần nào.
Trong thực tế, phiên bản gọn gàng nhất của chương trình này dùng break kèm giá trị, như bạn đã thấy ở trên: let answer = loop { ... break n * n; ... };. Dù theo cách nào, bài học vẫn vậy: khi ý bạn là “mãi mãi, cho tới khi tôi break”, hãy viết loop.
Khi nào dùng loop
Phần tiêu đề “Khi nào dùng loop”loop là lựa chọn đúng khi bạn không biết trước sẽ lặp bao nhiêu lần — bạn đang chờ một điều kiện nào đó trở thành đúng, chứ không phải đếm qua một khoảng hay một danh sách. Để đếm hoặc duyệt qua một collection, while và for (học ở các bài tiếp theo) thường dễ đọc hơn.
Luyện tập
Phần tiêu đề “Luyện tập”1. Đếm ngược để phóng tàu
Phần tiêu đề “1. Đếm ngược để phóng tàu”Dùng loop để in một dãy đếm ngược từ 5 về 1, rồi in Phóng!. Gợi ý: bắt đầu với let mut n = 5;, và break khi n về 0.
Xem lời giải
fn main() { let mut n = 5;
loop { if n == 0 { break; } println!("{n}..."); n -= 1; }
println!("Phóng!");}Kết quả:
5...4...3...2...1...Phóng!Bước kiểm tra đứng trước, nên khi n bằng 0 vòng lặp dừng lại trước khi in ra 0....
2. Lũy thừa đầu tiên của 2 lớn hơn 1000
Phần tiêu đề “2. Lũy thừa đầu tiên của 2 lớn hơn 1000”Bắt đầu từ 1 và cứ nhân đôi. Dùng break kèm giá trị để lấy con số đầu tiên lớn hơn 1000, và đếm xem đã nhân đôi bao nhiêu lần. Gợi ý: giữ một biến đếm mut bên ngoài vòng lặp, và viết let power = loop { ... };.
Xem lời giải
fn main() { let mut value = 1; let mut doublings = 0;
let power = loop { value *= 2; doublings += 1; if value > 1000 { break value; } };
println!("{power} sau {doublings} lần nhân đôi");}Kết quả:
1024 sau 10 lần nhân đôibreak value; kết thúc vòng lặp và trao value cho power. Biến đếm nằm bên ngoài vòng lặp, nên nó giữ nguyên giá trị sau khi vòng lặp kết thúc.
Tóm tắt
Phần tiêu đề “Tóm tắt”looplặp mãi mãi cho tới khi mộtbreakdừng nó lại — luôn đảm bảo có mộtbreak.break value;dừng vòng lặp và trả vềvaluelàm kết quả của cả biểu thức vòng lặp.- Hãy viết
loop, không phảiwhile true: Rust biết thânloopluôn chạy, điều này giúp nó kiểm tra các biến của bạn. - Dùng
loopkhi bạn lặp “cho tới khi một điều kiện xảy ra”, không phải khi đếm một số lần đã biết trước.
Kiểm tra nhanh
Phần tiêu đề “Kiểm tra nhanh”Kiểm tra nhanh
1. Điều gì giúp một loop trần không chạy mãi mãi?
2. Viết break count * 2; bên trong một vòng lặp có tác dụng gì?
3. Theo trang này, khi nào loop là lựa chọn tốt hơn while hay for?
4. Chuyện gì xảy ra nếu bạn viết while true { ... } trong Rust?
Điểm: 0 / 4
Đọc thêm
Phần tiêu đề “Đọc thêm”- Repetition with Loops — The Rust Book (tiếng Anh): phần giới thiệu chính thức về
loop,whilevàfor. - Returning Values from Loops — The Rust Book (tiếng Anh): một phần ngắn về
breakkèm giá trị. - loop — Rust by Example (tiếng Anh): ví dụ chạy được về
loop,breakvàcontinue. - Returning from loops — Rust by Example (tiếng Anh): thêm một ví dụ nhỏ về vòng lặp trả lại giá trị.
- The
loopkeyword — standard library docs (tiếng Anh): tài liệu tra cứu gọn gàng về cáchloopvàbreakphối hợp với nhau.