Giao diện
Common Collections std::collections
Ba cấu trúc dữ liệu bạn sẽ dùng 90% thời gian: Vector, String, và HashMap
Khác với array hay tuple, Collections lưu dữ liệu trên Heap, nghĩa là kích thước có thể thay đổi lúc runtime.
1. Vec<T>: Dynamic Array
Vector cho phép lưu list các value cùng type, liền kề nhau trong memory.
Tạo mới và Thêm phần tử
rust
fn main() {
// Tạo rỗng
let mut v: Vec<i32> = Vec::new();
// Macro tiện ích (phổ biến)
let mut v2 = vec![1, 2, 3];
// Thêm phần tử (Heap allocation có thể xảy ra)
v2.push(4);
v2.push(5);
}Truy cập phần tử
Có 2 cách: Indexing (unsafe-ish) và get (safe).
rust
let v = vec![1, 2, 3, 4, 5];
// 1. Indexing: Panics nếu out of bounds
let third: &i32 = &v[2];
println!("The third element is {}", third);
// 2. Get method: Trả về Option<&T>
match v.get(100) {
Some(third) => println!("The element is {}", third),
None => println!("There is no element at index 100."),
}Ownership & Borrowing với Vector
rust
let mut v = vec![1, 2, 3, 4, 5];
let first = &v[0]; // Immutable borrow
v.push(6); // Mutable borrow -> Resize có thể xảy ra (allocate vùng nhớ mới)
// println!("The first element is: {}", first);
// ❌ ERROR: first trỏ đến vùng nhớ cũ đã bị free sau khi resize!2. String: UTF-8 Encoded Text
Trong Rust, String phức tạp hơn bạn nghĩ vì nó hỗ trợ UTF-8 đầy đủ.
String: Owned, growable, heap-allocated (giốngVec<u8>nhưng đảm bảo UTF-8).&str: String slice, view vào string (thường là static hoặc borrow từString).
Tại sao không nên index String?
rust
let s = String::from("hello");
// let h = s[0]; // ❌ ERROR: Rust không hỗ trợ string indexingLý do: UTF-8. Một ký tự có thể tốn 1 đến 4 bytes.
"hello": mỗi char 1 byte."xin chào":chàodùng nhiều bytes hơn."Здравствуйте": mỗi char 2 bytes.
Index [0] không chắc chắn trả về ký tự mong muốn hoặc hợp lệ.
Slicing String (Cẩn thận!)
rust
let hello = "Здравствуйте";
let s = &hello[0..4]; // "Зд" (2 ký tự đầu, mỗi ký tự 2 bytes)
// let s = &hello[0..1]; // ❌ PANIC runtime: byte index 1 không phải biên ký tựIterating over Strings
Dùng .chars() hoặc .bytes() để rõ ràng:
rust
for c in "Зд".chars() {
println!("{}", c); // In ra ký tự
}
for b in "Зд".bytes() {
println!("{}", b); // In ra raw bytes
}3. HashMap<K, V>: Key-Value Store
Lưu dữ liệu dạng cặp Key-Value, truy cập O(1) trung bình. Dùng SipHash mặc định (chống DoS attack) nên an toàn nhưng chậm hơn một chút so với một số hash function khác.
Cơ bản
rust
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
// Truy cập
let team_name = String::from("Blue");
let score = scores.get(&team_name); // Option<&i32>
}Ownership
Đối với types implement Copy (i32), value được copy vào HashMap. Đối với String, HashMap sẽ chiếm quyền ownership (move).
rust
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
let mut map = HashMap::new();
map.insert(field_name, field_value);
// field_name và field_value không còn valid ở đâyUpdating Values
rust
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
// 1. Overwrite
scores.insert(String::from("Blue"), 25);
// 2. Insert if not exists (Entry API - Idiomatic!)
scores.entry(String::from("Yellow")).or_insert(50);
scores.entry(String::from("Blue")).or_insert(50); // Không làm gì vì đã có
// 3. Update based on old value
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0); // Trả về &mut v
*count += 1; // Deref để cộng
}
println!("{:?}", map);Bảng Tóm tắt Collections
| Collection | Use Case | Performance Note |
|---|---|---|
Vec<T> | List, Stack | Resize tốn kém (O(n)), push back O(1). |
String | Text processing | UTF-8 overhead, indexing không O(1). |
HashMap | Hash Table, Dictionary | O(1) lookup. Order không đảm bảo. |
BTreeMap | Ordered Map | O(log n). Luôn sorted theo key. |
HashSet | Unique items | Giống HashMap nhưng chỉ có Key. |