Skip to content

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ống Vec<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 indexing

Lý 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ào dù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 ở đây

Updating 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

CollectionUse CasePerformance Note
Vec<T>List, StackResize tốn kém (O(n)), push back O(1).
StringText processingUTF-8 overhead, indexing không O(1).
HashMapHash Table, DictionaryO(1) lookup. Order không đảm bảo.
BTreeMapOrdered MapO(log n). Luôn sorted theo key.
HashSetUnique itemsGiống HashMap nhưng chỉ có Key.