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

Kiểu dữ liệu trong Rust

Mọi giá trị trong Rust đều có một kiểu (type) — một cái nhãn cho trình biên dịch biết đó là loại dữ liệu gì (số nguyên, số thập phân, văn bản, đúng/sai, v.v.). Biết được kiểu giúp Rust kiểm tra lỗi trong code của bạn trước khi nó chạy.

Như bạn đã thấy ở bài Biến, Rust thường có thể suy luận kiểu cho bạn. Nhưng biết tên các kiểu chính vẫn rất có ích, vì bạn sẽ gặp chúng trong thông báo lỗi và trong chữ ký hàm.

Số nguyên (integer) là những số không có dấu thập phân, như 42 hay -7. Rust có nhiều kiểu số nguyên, khác nhau ở kích thước và việc có cho phép số âm hay không:

Kiểu Có dấu? Cách dùng thường gặp
i32 Có (có thể âm) Kiểu mặc định — hãy dùng nó trừ khi bạn có lý do khác
u32 Không (từ 0 trở lên) Số đếm, kích thước, những thứ không thể âm
i64 / u64 Có / Không Những số rất lớn
usize Không Chỉ số (index) để truy cập vào collection
fn main() {
let temperature = -5; // mặc định là i32
let count: u32 = 100; // ghi rõ là số không dấu
println!("{temperature} độ, số lượng là {count}");
}

Kết quả:

-5 độ, số lượng là 100
▶ Tự chạy thử

Số thực dấu phẩy động (số thập phân)

Phần tiêu đề “Số thực dấu phẩy động (số thập phân)”

Với những số có phần thập phân, hãy dùng kiểu số thực dấu phẩy động (floating-point). Có hai kiểu: f64 (mặc định, độ chính xác kép) và f32.

fn main() {
let pi = 3.14159; // mặc định là f64
let price: f32 = 9.99;
println!("Pi là {pi}, giá là {price}");
}

Kết quả:

Pi là 3.14159, giá là 9.99
▶ Tự chạy thử

Hãy dùng f64 trừ khi bạn thực sự cần kiểu f32 nhỏ hơn — f64 chính xác hơn và trên phần cứng hiện đại thì chạy nhanh không kém.

Một boolean (bool) là kiểu đơn giản nhất: nó chỉ có thể là true (đúng) hoặc false (sai). Bạn sẽ dùng chúng liên tục trong câu lệnh if và các điều kiện.

fn main() {
let is_logged_in = true;
let has_permission: bool = false;
println!("đã đăng nhập: {is_logged_in}, có quyền: {has_permission}");
}

Kết quả:

đã đăng nhập: true, có quyền: false
▶ Tự chạy thử

Một char chứa một ký tự duy nhất, được viết trong dấu nháy đơn ' '. Một char của Rust có thể là bất kỳ giá trị vô hướng Unicode (Unicode scalar value) nào — bao gồm hầu hết emoji, dù một số emoji phức tạp (như lá cờ hoặc emoji ghép từ nhiều ký tự nối với nhau) không vừa trong một char.

fn main() {
let letter = 'R';
let symbol = '$';
let crab = '🦀';
println!("{letter} {symbol} {crab}");
}

Kết quả:

R $ 🦀
▶ Tự chạy thử

Văn bản trong Rust được viết trong dấu nháy kép. Có hai kiểu chuỗi (string) bạn sẽ gặp:

  • &str — một string slice (lát chuỗi), thường là văn bản bạn viết trực tiếp trong code (một “string literal”).
  • String — một đoạn văn bản có thể nới rộng, có chủ sở hữu, mà bạn có thể thay đổi và ghép thêm.
fn main() {
let greeting = "Xin chào"; // &str
let mut name = String::from("Ferris"); // String
name.push_str(" chú cua"); // String có thể dài thêm
println!("{greeting}, {name}!");
}

Kết quả:

Xin chào, Ferris chú cua!
▶ Tự chạy thử

Đừng lo về sự khác nhau giữa &str và String vội — nó liên quan đến quyền sở hữu (ownership), thứ bạn sẽ học sớm thôi. Hiện tại: dùng "..." cho văn bản, và dùng String khi bạn cần tạo dựng hay sửa đổi nó.

Phần lớn thời gian Rust tự suy luận kiểu. Nhưng đôi khi nó cần một gợi ý — ví dụ khi chuyển văn bản thành số (bạn sẽ thấy điều đó ở bài Ép kiểu). Bạn thêm kiểu bằng dấu hai chấm, gọi là chú thích kiểu (type annotation):

let x: i32 = 42;
let y: f64 = 3.5;
let active: bool = true;
Kiểu Chứa gì Ví dụ
i32 Số nguyên (mặc định) let n = 42;
u32 Số nguyên không âm let n: u32 = 42;
f64 Số thập phân (mặc định) let pi = 3.14;
bool true hoặc false let ok = true;
char Một ký tự let c = 'A';
&str Văn bản viết trực tiếp let s = "hi";
String Văn bản có thể nới rộng let s = String::from("hi");

Mô tả một nhân vật game bằng một biến cho mỗi kiểu: tên (&str), cấp độ (i32), phần trăm máu (f64), cờ is_online (bool) và một chữ cái xếp hạng (char). In tất cả trên một dòng. Gợi ý: char dùng dấu nháy đơn, văn bản dùng dấu nháy kép.

Xem lời giải
fn main() {
let name = "Ferris"; // &str
let level = 7; // i32
let health = 82.5; // f64
let is_online = true; // bool
let rank = 'A'; // char
println!("{name} | cấp {level} | {health}% | trực tuyến: {is_online} | hạng {rank}");
}

Kết quả:

Ferris | cấp 7 | 82.5% | trực tuyến: true | hạng A
▶ Tự chạy thử

Bắt đầu với String::from("Rust"), rồi thêm " nhanh" và " và an toàn" vào nó, và in kết quả ra. Gợi ý: String phải được khai báo với mut thì push_str mới thay đổi được nó.

Xem lời giải
fn main() {
let mut sentence = String::from("Rust");
sentence.push_str(" nhanh");
sentence.push_str(" và an toàn");
println!("{sentence}");
}

Kết quả:

Rust nhanh và an toàn
▶ Tự chạy thử
  • Mọi giá trị đều có một kiểu; Rust thường tự suy luận nó.
  • Số nguyên → i32 (mặc định). Số thập phân → f64 (mặc định).
  • bool là true/false; char là một ký tự đặt trong dấu nháy đơn.
  • Văn bản được viết trong dấu nháy kép: &str cho văn bản viết trực tiếp, String cho văn bản có thể nới rộng.

Kiểm tra nhanh

1. Kiểu số nguyên mặc định trong Rust là gì nếu bạn không ghi rõ?

2. Rust phân biệt một ký tự char với một chuỗi viết trực tiếp như thế nào?

3. Kiểu nào là đoạn văn bản có thể nới rộng, có chủ sở hữu và sửa đổi được?

4. Kiểu số thực mặc định trong Rust là gì?

5. let greeting = "Hello"; sẽ được suy luận ra kiểu nào?

Điểm: 0 / 5

  • Data Types — The Rust Book (tiếng Anh): mọi kiểu vô hướng cùng kích thước và phạm vi giá trị, cộng thêm tràn số nguyên và các kiểu phức hợp (tuple và mảng).
  • Primitives — Rust by Example (tiếng Anh): ví dụ chạy được cho từng kiểu cơ bản, kèm phần tiếp theo về literal như 1_000 và 0x80.
  • i32 — standard library docs (tiếng Anh): giá trị nhỏ nhất và lớn nhất (i32::MIN, i32::MAX) và rất nhiều phương thức mà các con số có.
  • char — standard library docs (tiếng Anh): giá trị vô hướng Unicode là gì, và vì sao một char luôn chiếm 4 byte.
  • String — standard library docs (tiếng Anh): String liên quan thế nào với &str, và mọi phương thức để tạo dựng và thay đổi văn bản.