Bỏ qua để đến nội dung

Cú pháp Rust

Giờ bạn đã chạy được Rust rồi, hãy chậm lại một chút và xem từng phần của một chương trình thực sự có ý nghĩa gì. Chúng ta sẽ dùng ví dụ nhỏ nhất có thể và tháo rời nó ra từng mảnh.

fn main() {
println!("Xin chào, thế giới!");
}

Kết quả:

Xin chào, thế giới!
▶ Tự chạy thử
fn main() {
// code của bạn chạy ở đây
}

Mọi chương trình Rust đều bắt đầu từ một hàm tên là main. Khi bạn chạy chương trình, Rust tìm main và chạy phần code bên trong nó.

  • fn là từ khóa để định nghĩa một hàm (một khối code có tên).
  • main là tên của hàm — cái tên cụ thể này rất đặc biệt; nó là điểm bắt đầu của chương trình.
  • () chứa các đầu vào của hàm (ở đây để trống — main không nhận gì cả).
  • Cặp ngoặc nhọn { } bao lấy thân hàm — phần code thuộc về hàm đó.

Câu lệnh kết thúc bằng dấu chấm phẩy

Phần tiêu đề “Câu lệnh kết thúc bằng dấu chấm phẩy”

Bên trong thân hàm, mỗi chỉ dẫn thường là một câu lệnh (statement), và câu lệnh kết thúc bằng dấu chấm phẩy ;:

fn main() {
let x = 5;
let y = 10;
println!("{}", x + y);
}

Kết quả:

15
▶ Tự chạy thử

Quên dấu chấm phẩy ở chỗ cần có là một trong những lỗi phổ biến nhất của người mới bắt đầu — và trình biên dịch sẽ chỉ thẳng vào nó.

Code Rust được tạo từ hai loại mảnh ghép, và sự khác biệt giữa chúng quan trọng trong Rust hơn hầu hết các ngôn ngữ khác:

  • Một câu lệnh (statement) làm một việc gì đó nhưng không trả lại giá trị. let x = 5; là một câu lệnh.
  • Một biểu thức (expression) tạo ra một giá trị. 5, x + 1 và x * 2 đều là biểu thức.

Đây là phần khiến mọi người bất ngờ: một khối code trong cặp ngoặc nhọn { } cũng là một biểu thức. Giá trị của nó là dòng cuối cùng, viết không có dấu chấm phẩy:

fn main() {
let x = 5;
let y = {
let doubled = x * 2; // một câu lệnh bên trong khối
doubled + 1 // không có dấu chấm phẩy: đây là giá trị của khối
};
println!("y bằng {y}");
}

Kết quả:

y bằng 11
▶ Tự chạy thử

Khối này chạy các câu lệnh bên trong, rồi trả lại doubled + 1, tức là 11, và giá trị đó trở thành y. Để ý dấu chấm phẩy sau dấu } đóng: cả dòng let y = ...; vẫn là một câu lệnh.

Nếu bạn thêm dấu chấm phẩy sau doubled + 1, nó không còn là giá trị của khối nữa. Khi đó khối trả lại “không có gì” (Rust viết điều đó là ()), và println! không in được nó, nên code sẽ không biên dịch được. Quy tắc “dòng cuối không có dấu chấm phẩy” này chính là cách các hàm trả về giá trị. Bạn sẽ gặp lại nó ở bài Hàm và khi dùng if như một biểu thức.

Nhìn kỹ println! — dấu chấm than đó không phải lỗi gõ nhầm. Dấu ! nghĩa là đây là một macro, không phải một hàm bình thường.

Bạn chưa cần hiểu hết về macro lúc này. Chỉ cần nhớ: khi thấy !, đó là một macro. Hiện tại macro duy nhất bạn dùng là println! để in chữ ra màn hình.

fn main() {
println!("Đây là một lời gọi macro");
}

Bên trong println!, cặp ngoặc nhọn {} là chỗ giữ chỗ (placeholder) sẽ được điền bằng các giá trị bạn truyền vào sau đoạn chữ:

fn main() {
let name = "Ferris";
let age = 10;
println!("{} năm nay {} tuổi", name, age);
}

Kết quả:

Ferris năm nay 10 tuổi
▶ Tự chạy thử

Bạn cũng có thể đặt tên biến trực tiếp vào trong cặp ngoặc, cách này thường gọn gàng hơn:

println!("{name} năm nay {age} tuổi");

Rust không quan tâm đến thụt lề như Python — nó dùng cặp ngoặc nhọn { } để biết một khối bắt đầu và kết thúc ở đâu. Thụt lề chỉ để con người đọc code dễ hơn.

Dù vậy, cộng đồng có một phong cách chuẩn, và Rust đi kèm một công cụ để tự động áp dụng nó:

Terminal window
cargo fmt

Chạy cargo fmt sẽ định dạng lại code của bạn theo phong cách chính thức. Hãy tập thói quen dùng nó.

Bạn có thể để lại ghi chú trong code mà Rust sẽ bỏ qua. Đó là chú thích (comment), và chúng bắt đầu bằng //:

fn main() {
// Đây là một chú thích — Rust bỏ qua nó
println!("Xin chào!"); // chú thích cũng có thể nằm ở cuối dòng
}

Chúng ta sẽ nói kỹ hơn về chú thích ở trang tiếp theo.

Tạo hai biến a = 7 và b = 3, rồi in ra 7 + 3 = 10. Hãy để Rust tự làm phép cộng. Gợi ý: một println! có thể có nhiều chỗ giữ chỗ {}, được điền lần lượt bằng các giá trị phía sau đoạn chữ.

Xem lời giải
fn main() {
let a = 7;
let b = 3;
println!("{} + {} = {}", a, b, a + b);
}

Kết quả:

7 + 3 = 10
▶ Tự chạy thử

Một cửa hàng bán 3 món, mỗi món giá 4, cộng thêm 2 tiền giao hàng. Hãy tính total bằng một khối { }: bên trong, tạo một biến subtotal, rồi trả lại subtotal + 2. In ra Tổng: 14. Gợi ý: dòng cuối của khối không được có dấu chấm phẩy.

Xem lời giải
fn main() {
let price = 4;
let quantity = 3;
let total = {
let subtotal = price * quantity;
subtotal + 2 // tiền giao hàng
};
println!("Tổng: {total}");
}

Kết quả:

Tổng: 14
▶ Tự chạy thử
  • Mọi chương trình đều bắt đầu từ hàm main.
  • Code nằm trong cặp ngoặc nhọn { }; phần lớn câu lệnh kết thúc bằng ;.
  • Câu lệnh làm một việc gì đó; biểu thức tạo ra một giá trị. Dòng cuối của một khối, không có ;, là giá trị của khối đó.
  • Dấu ! (như trong println!) nghĩa là đó là một macro.
  • {} bên trong println! là chỗ giữ chỗ, được điền bằng các giá trị bạn truyền vào.
  • Thụt lề là để dễ đọc — chạy cargo fmt để tự động định dạng.

Kiểm tra nhanh

1. Hàm main trong một chương trình Rust có gì đặc biệt?

2. Dấu ! sau println có nghĩa là gì?

3. Giá trị của y sau let y = { let a = 2; a + 1 }; là bao nhiêu?

Điểm: 0 / 3