Hàm, Biểu Thức, Và Luồng Điều Khiển: Bí Quyết Viết Logic Mượt Mà Trong Rust
Tiếp nối phần tìm hiểu về cách lưu trữ dữ liệu với biến và kiểu dữ liệu ở bài trước, chúng ta sẽ chuyển sang một phần cực kỳ quan trọng để định hình tư duy viết code: Cách xây dựng các hàm logic, phân biệt rõ biểu thức với câu lệnh và điều hướng luồng chương trình.
Thoạt nhìn, cú pháp điều khiển luồng hay khai báo hàm của Rust khá quen thuộc nếu bạn đã từng làm việc qua C, C++ hay JavaScript. Tuy nhiên, nếu không nắm vững những nguyên lý đặc thù bên dưới — đặc biệt là quy tắc về Expression và Statement — bạn sẽ rất dễ gặp phải những lỗi biên dịch "dở khóc dở cười". Cùng mổ xẻ chi tiết ngay dưới đây.
⚙️ 1. Hàm (Functions) và Quy tắc định nghĩa trong Rust
Hàm là khối xây dựng cơ bản trong mọi ứng dụng Rust. Từ khóa fn được dùng để khai báo một hàm mới.
- Quy chuẩn đặt tên: Rust tuân thủ nghiêm ngặt chuẩn snake_case (tất cả viết thường, cách nhau bằng dấu gạch dưới _) cho cả tên hàm lẫn tên biến.
- Kiểm tra kiểu dữ liệu tĩnh: Khác với các ngôn ngữ kiểu động, bạn bắt buộc phải chỉ định tường minh kiểu dữ liệu cho mọi tham số truyền vào hàm.
fn main() {
println!("Starting program...");
print_greeting("MrSea Dev", 44);
}
// Hàm nhận hai tham số với kiểu dữ liệu được định nghĩa rõ ràng
fn print_greeting(name: &str, age: u32) {
println!("Hello {name}! You are {age} years old.");
}
Cơ chế trả về giá trị từ hàm
Trong Rust, bạn hiếm khi phải dùng đến từ khóa return ở cuối hàm. Theo triết lý thiết kế của ngôn ngữ, hàm sẽ tự động trả về giá trị của biểu thức cuối cùng nằm trong thân hàm.
fn main() {
let result = add_numbers(10, 20);
println!("The addition result is: {result}");
}
// Khai báo kiểu dữ liệu trả về bằng mũi tên `->`
fn add_numbers(a: i32, b: i32) -> i32 {
a + b // ⚠️ TUYỆT ĐỐI KHÔNG có dấu chấm phẩy `;` ở đây! Đây là một expression trả về giá trị.
}
Kinh nghiệm thực chiến: Lỗi kinh điển mà hầu hết lập trình viên mới làm quen với Rust đều mắc phải là lỡ tay thêm dấu chấm phẩy ; vào sau dòng cuối cùng (a + b;). Khi đó, biểu thức biến thành một câu lệnh trả về kiểu rỗng đơn vị (), và trình biên dịch sẽ lập tức quăng ra một đống lỗi type mismatch. Hãy cực kỳ lưu ý điểm này!
📜 2. Điểm mấu chốt: Biểu thức (Expressions) và Câu lệnh (Statements)
Hiểu đúng bản chất của Statement và Expression sẽ giúp bạn viết code Rust cực kỳ gọn gàng và tự nhiên:
- Câu lệnh (Statements): Là các chỉ thị thực hiện một hành động nào đó nhưng không trả về giá trị. Ví dụ: lệnh khai báo biến let x = 6; là một statement. Nó chỉ làm nhiệm vụ lưu trữ, không sinh ra bất kỳ giá trị nào để gán tiếp cho một biến khác.
- Biểu thức (Expressions): Luôn đánh giá để trả về một giá trị kết quả. Ví dụ: một phép tính đơn giản 5 + 6, một lời gọi hàm, hay thậm chí một khối mã lệnh độc lập { let x = 3; x + 1 } đều được tính là expressions.
Chính nhờ việc các khối điều kiện trong Rust hoạt động dưới dạng biểu thức, bạn có thể viết những đoạn code cực kỳ ngắn gọn như thế này:
fn main() {
let is_active = true;
// Khối if là một expression, kết quả trả về được gán thẳng cho status_code
let status_code = if is_active {
5
} else {
6
};
println!("The value of status_code is: {status_code}");
}
🔀 3. Cấu trúc điều khiển (Control Flow)
A. Điều kiện rẽ nhánh với if / else
Cú pháp if khá trực quan, nhưng có một nguyên tắc cứng rắn: Rust không tự động ép kiểu các giá trị khác thành kiểu boolean giống như JavaScript hay Python. Biểu thức điều kiện bắt buộc phải đánh giá ra kiểu bool (true hoặc false).
fn main() {
let number = 3;
if number < 5 {
println!("Number is less than 5");
} else if number == 5 {
println!("Number is equal to 5");
} else {
println!("Number is greater than 5");
}
}
B. Vòng lặp vô hạn với loop
loop tạo ra một vòng lặp chạy vô thời hạn cho đến khi bạn chủ động ngắt nó bằng từ khóa break. Điểm hay là loop cũng có thể trả về một giá trị thông qua lệnh break.
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2; // Thoát vòng lặp và trả về giá trị 20 cho biến result
}
};
println!("Value received from loop: {result}");
}
C. Vòng lặp kiểm tra điều kiện với while
Dùng khi bạn muốn lặp lại một khối mã dựa trên việc kiểm tra điều kiện đúng/sai ở đầu mỗi chu kỳ lặp.
fn main() {
let mut count = 3;
while count > 0 {
println!("{count}!");
count -= 1;
}
println!("Liftoff! 🚀");
}
D. Vòng lặp tập hợp an toàn với for
for là công cụ lặp được sử dụng nhiều nhất trong thực tế vì tính an toàn, không lo vượt quá giới hạn mảng (out-of-bounds) và cú pháp cực kỳ gọn gàng khi làm việc với các dãy số hoặc tập hợp.
fn main() {
// Duyệt qua một khoảng giá trị từ 1 đến 4 (số 5 sẽ bị loại trừ)
for i in 1..5 {
println!("Value of i: {i}");
}
// Duyệt qua các phần tử của một mảng tĩnh
let items = [10, 20, 30, 40, 50];
for item in items {
println!("Element in array: {item}");
}
}
Toàn bộ các cấu trúc logic cơ bản đã được thiết lập xong. Ở bài viết tiếp theo, chúng ta sẽ bước vào thử thách lớn nhất và cũng là "đặc sản" cốt lõi làm nên tên tuổi của ngôn ngữ này — Ownership (Quyền sở hữu) và cách quản lý bộ nhớ trên Stack/Heap. Hãy chuẩn bị tinh thần thật vững vàng nhé!
Bình luận