Kiểm soát luồng chương trình của bạn với sức mạnh của Rust!
Giới thiệu: Tại sao câu lệnh điều kiện lại quan trọng?
Chào mừng các bạn đến với hành trình khám phá Rust! Trong bất kỳ ngôn ngữ lập trình nào, khả năng ra quyết định và thực hiện các hành động khác nhau dựa trên các điều kiện cụ thể là vô cùng quan trọng. Đây chính là lúc các câu lệnh điều kiện phát huy vai trò của mình. Chúng giúp chương trình của bạn trở nên thông minh hơn, linh hoạt hơn, và có khả năng phản ứng với nhiều tình huống khác nhau.
Trong bài viết này, chúng ta sẽ đi sâu vào các câu lệnh điều kiện cơ bản và mạnh mẽ nhất mà Rust cung cấp: if/else, if let, và match. Hãy cùng tìm hiểu cách sử dụng chúng để kiểm soát luồng chương trình của bạn một cách hiệu quả và an toàn!
1. Câu Lệnh if/else Cơ Bản
Cũng giống như nhiều ngôn ngữ khác, Rust sử dụng câu lệnh if để kiểm tra một điều kiện và thực thi một khối mã nếu điều kiện đó là đúng. Bạn có thể mở rộng nó với else if để kiểm tra nhiều điều kiện liên tiếp và else để xử lý trường hợp không có điều kiện nào đúng.
Cú pháp cơ bản của if/else
Điều kiện trong Rust phải luôn là một biểu thức trả về kiểu bool (true hoặc false). Rust không tự động ép kiểu các giá trị khác thành boolean như một số ngôn ngữ khác.
fn main() {
let so_nguyen = 10;
if so_nguyen < 5 {
println!("Số nguyên nhỏ hơn 5");
} else if so_nguyen < 15 {
println!("Số nguyên nằm giữa 5 và 14");
} else {
println!("Số nguyên lớn hơn hoặc bằng 15");
}
}
Trong ví dụ trên, chương trình sẽ in ra “Số nguyên nằm giữa 5 và 14” vì 10 không nhỏ hơn 5 nhưng nhỏ hơn 15.
if là một biểu thức (Expression)
Một điểm đặc biệt và rất mạnh mẽ của Rust là if là một biểu thức, nghĩa là nó có thể trả về một giá trị. Điều này cho phép bạn viết mã ngắn gọn và rõ ràng hơn. Các khối mã trong if và else phải trả về cùng kiểu dữ liệu.
fn main() {
let number = 7;
let ket_qua = if number % 2 == 0 {
"Số chẵn"
} else {
"Số lẻ"
};
println!("{} là: {}", number, ket_qua); // Output: 7 là: Số lẻ
}
Thật tuyệt vời phải không? Thay vì khai báo một biến và gán giá trị cho nó trong từng nhánh if/else, bạn có thể gán trực tiếp kết quả của biểu thức if.
2. Câu Lệnh if let (Conditional Assignment)
Khi làm việc với các kiểu dữ liệu enum như Option hoặc Result, bạn thường muốn thực hiện một hành động chỉ khi giá trị đó khớp với một biến thể cụ thể (ví dụ: khi Option là Some hoặc Result là Ok). Trong những trường hợp này, if let là một cú pháp tiện lợi hơn so với match đầy đủ.
if let cho phép bạn kết hợp kiểm tra mẫu (pattern matching) với một điều kiện if, giúp mã của bạn gọn gàng hơn khi bạn chỉ quan tâm đến một trường hợp duy nhất.
fn main() {
let some_value = Some(3); // Kiểu Option<i32>
// Sử dụng if let để kiểm tra nếu some_value là Some(x)
if let Some(x) = some_value {
println!("Giá trị bên trong Some là: {}", x); // Output: Giá trị bên trong Some là: 3
} else {
println!("Không phải là Some");
}
let none_value: Option<i32> = None;
if let Some(y) = none_value {
println!("Giá trị bên trong Some là: {}", y);
} else {
println!("Không phải là Some"); // Output: Không phải là Some
}
}
if let giúp giảm bớt “boilerplate” code khi bạn chỉ cần xử lý một trường hợp cụ thể của enum. Nó có thể có một khối else tùy chọn để xử lý tất cả các trường hợp khác.
3. Câu Lệnh match (Pattern Matching Mạnh Mẽ)
match là một trong những tính năng mạnh mẽ và đặc trưng nhất của Rust, cho phép bạn so sánh một giá trị với một loạt các mẫu (patterns) và thực thi mã dựa trên mẫu khớp. Nó mạnh hơn if/else vì nó đảm bảo tính toàn diện (exhaustiveness) – bạn phải xử lý tất cả các trường hợp có thể của giá trị bạn đang match, hoặc sử dụng một mẫu bắt tất cả (catch-all) như _.
Cú pháp cơ bản của match
fn main() {
let diem_so = 85;
match diem_so {
90..=100 => println!("Điểm A"), // Phạm vi từ 90 đến 100
80..=89 => println!("Điểm B"), // Phạm vi từ 80 đến 89
70..=79 => println!("Điểm C"),
_ => println!("Điểm D hoặc F"), // Mẫu bắt tất cả các trường hợp còn lại
}
// Output: Điểm B
}
Trong ví dụ này, diem_so được so sánh với các mẫu khác nhau. Dấu => ngăn cách mẫu và mã sẽ được thực thi. Mẫu _ là một “catch-all” và phải luôn là nhánh cuối cùng nếu bạn không muốn liệt kê tất cả các trường hợp có thể.
match với Enum
match đặc biệt hữu ích khi làm việc với các enum trong Rust. Nó giúp bạn xử lý từng biến thể của enum một cách rõ ràng và an toàn.
enum TrangThaiDenGiaoThong {
Do,
Vang,
Xanh,
}
fn xu_ly_den(den: TrangThaiDenGiaoThong) {
match den {
TrangThaiDenGiaoThong::Do => println!("Dừng lại!"),
TrangThaiDenGiaoThong::Vang => println!("Chuẩn bị dừng hoặc đi!"),
TrangThaiDenGiaoThong::Xanh => println!("Được phép đi!"),
}
}
fn main() {
let den_hien_tai = TrangThaiDenGiaoThong::Do;
xu_ly_den(den_hien_tai); // Output: Dừng lại!
xu_ly_den(TrangThaiDenGiaoThong::Xanh); // Output: Được phép đi!
}
Trong ví dụ này, compiler Rust sẽ đảm bảo rằng bạn đã xử lý tất cả các biến thể của TrangThaiDenGiaoThong. Nếu bạn bỏ sót một trường hợp, Rust sẽ cảnh báo bạn, giúp ngăn ngừa lỗi trong quá trình phát triển.
match cũng là một biểu thức
Tương tự như if, match cũng là một biểu thức và có thể trả về một giá trị. Điều này làm cho nó cực kỳ linh hoạt!
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
fn main() {
let dong_xu = Coin::Nickel;
let gia_tri = value_in_cents(dong_xu);
println!("Đồng xu Nickel có giá trị: {} xu", gia_tri); // Output: Đồng xu Nickel có giá trị: 5 xu
}
Đây là một ví dụ điển hình về cách match có thể được sử dụng để ánh xạ các biến thể enum thành các giá trị khác.
Kết luận: Lựa chọn câu lệnh điều kiện phù hợp
Bạn đã đi qua ba công cụ mạnh mẽ để kiểm soát luồng chương trình trong Rust: if/else, if let, và match. Mỗi công cụ có ưu điểm riêng và phù hợp với các tình huống khác nhau:
if/else: Tuyệt vời cho các điều kiện boolean đơn giản hoặc chuỗi điều kiện tuyến tính. Khi cần gán giá trị dựa trên điều kiện, hãy nhớ rằngiflà một biểu thức.if let: Là lựa chọn lý tưởng khi bạn chỉ quan tâm đến một mẫu cụ thể củaenum(nhưSomehoặcOk) và muốn tránh sự dài dòng củamatchđầy đủ.match: Là công cụ mạnh nhất cho việc so khớp mẫu toàn diện, đặc biệt khi làm việc vớienumcó nhiều biến thể. Nó đảm bảo tính an toàn và giúp bạn xử lý mọi trường hợp có thể.
Việc nắm vững các câu lệnh điều kiện này là chìa khóa để viết mã Rust hiệu quả, dễ đọc và an toàn. Hãy thực hành thật nhiều với các ví dụ khác nhau để củng cố kiến thức của bạn.
Cảm ơn bạn đã theo dõi bài viết này! Hẹn gặp lại trong các bài viết tiếp theo về lập trình Rust cơ bản!






