Vec<T> is Rust's most common dynamic array type. It stores multiple elements of the same type contiguously on the heap. When a vector needs more space it reallocates automatically.
Vec<T> là mảng động (growable array) phổ biến nhất trong Rust. Nó lưu trữ nhiều phần tử cùng kiểu liên tiếp trong bộ nhớ heap. Khi vector cần thêm chỗ, nó tự động cấp phát lại bộ nhớ.
1fn main() {2 // Create an empty vector and push values3 let mut v: Vec<i32> = Vec::new();4 v.push(1);5 v.push(2);6 v.push(3);78 // Create with initial values using the vec! macro9 let v2 = vec![10, 20, 30, 40, 50];1011 // Reading elements12 let third = &v2[2]; // panics if out of boundsDùng .get(i) thay vì v[i] khi index có thể không hợp lệ — nó trả về Option<&T> thay vì panic.
When iterating over a vector you must decide whether you want immutable references, mutable references, or to consume the vector by taking ownership. Each form has different semantics.
Khi lặp qua một vector, bạn phải quyết định liệu mình muốn tham chiếu bất biến, tham chiếu có thể thay đổi, hay tiêu thụ vector (lấy quyền sở hữu). Mỗi cách có ngữ nghĩa khác nhau.
1fn main() {2 let v = vec![1, 2, 3, 4, 5];34 // Immutable iteration — borrows vector5 for x in &v {6 print!("{x} "); // x is &i327 }8 println!();9 println!("v still usable: {:?}", v);1011 // Mutable iteration — mutably borrows12 let mut v2 = vec![1, 2, 3];A Rust String is an owned, growable UTF-8 byte sequence. Not every byte sequence is valid UTF-8, so Rust separates String (valid UTF-8) from Vec<u8> (raw bytes). Any indexing must be done carefully because characters can be multiple bytes wide.
String trong Rust là một chuỗi byte UTF-8 được sở hữu, có thể phát triển. Không phải mọi chuỗi byte đều là UTF-8 hợp lệ, vì vậy Rust tách biệt String (UTF-8 hợp lệ) với Vec<u8> (byte thô). Mọi chỉ số theo byte đều cần xử lý cẩn thận.
1fn main() {2 // Creating strings3 let s1 = String::new();4 let s2 = String::from("hello");5 let s3 = "world".to_string();6 let s4 = format!("{s2} {s3}");7 println!("{s4}"); // hello world89 // UTF-8: each char can be 1–4 bytes10 let emoji = String::from("Hello");11 println!("bytes: {}", emoji.len()); // byte length, not char count12 println!("chars: {}", emoji.chars().count()); // actual character countString không thể được lập chỉ mục bằng số nguyên vì một ký tự Unicode có thể chiếm nhiều byte. Rust ưu tiên sự chính xác hơn sự thuận tiện ở đây.
Rust provides many methods for string manipulation. String slicing (&str) works on byte boundaries, so always ensure your indices land on valid character boundaries.
Rust cung cấp nhiều phương thức cho việc thao tác chuỗi. Cắt chuỗi (&str) hoạt động trên ranh giới byte, vì vậy luôn đảm bảo các chỉ số của bạn nằm trên ranh giới ký tự hợp lệ.
1fn main() {2 let mut s = String::from("hello");34 // Concatenation5 s.push(' ');6 s.push_str("world");7 println!("{s}"); // hello world89 // + operator moves left-hand side10 let s1 = String::from("Hello, ");11 let s2 = String::from("world!");12 let s3 = s1 + &s2; // s1 is moved here, s2 is borrowedHashMap stores key-value pairs and allows O(1) average lookup by key. Keys must implement the Eq and Hash traits.
HashMap lưu trữ các cặp khóa-giá trị và cho phép tra cứu theo khóa trong thời gian O(1) trung bình. Khóa phải triển khai các trait Eq và Hash.
1use std::collections::HashMap;23fn main() {4 // Create and populate5 let mut scores: HashMap<String, i32> = HashMap::new();6 scores.insert(String::from("Alice"), 100);7 scores.insert(String::from("Bob"), 85);8 scores.insert(String::from("Carol"), 92);910 // Build from iterators11 let names = vec!["Alice", "Bob"];12 let points = vec![100, 85];The Entry API is the most idiomatic way to update a HashMap because it avoids looking up the key twice. It returns an Entry enum that lets you manipulate the value depending on whether the key exists.
Entry API là cách thành ngữ nhất để cập nhật HashMap vì nó tránh việc tra cứu khóa hai lần. Nó trả về một enum Entry cho phép bạn thao tác với giá trị tùy thuộc vào việc khóa đó có tồn tại hay không.
1use std::collections::HashMap;23fn main() {4 let mut scores: HashMap<String, i32> = HashMap::new();56 // Insert only if key is absent7 scores.entry(String::from("Yellow")).or_insert(50);8 scores.entry(String::from("Yellow")).or_insert(200); // no effect9 println!("{scores:?}"); // {"Yellow": 50}1011 // Insert with a default computed value12 scores.entry(String::from("Blue")).or_insert_with(|| 42 * 2);HashSet is a HashMap with no values — it stores only unique keys. It is useful for membership testing and deduplication. HashSet supports standard set operations: union, intersection, difference.
HashSet là HashMap không có giá trị — nó chỉ lưu trữ các khóa duy nhất. Nó hữu ích để kiểm tra thành viên và loại bỏ trùng lặp. HashSet hỗ trợ các phép toán tập hợp chuẩn: union, intersection, difference.
1use std::collections::HashSet;23fn main() {4 let mut set: HashSet<i32> = HashSet::new();5 set.insert(1);6 set.insert(2);7 set.insert(3);8 set.insert(2); // duplicate, ignored9 println!("{set:?}"); // {1, 2, 3} (order not guaranteed)1011 // Membership12 println!("{}", set.contains(&2)); // trueChoosing the right collection significantly affects both performance and code readability. Here is practical guidance.
Chọn đúng bộ sưu tập ảnh hưởng đáng kể đến hiệu suất và tính đọc được của code. Dưới đây là hướng dẫn thực hành.
- Vec<T> — ordered list, index access, frequent appending to the end
Vec<T> — danh sách có thứ tự, truy cập theo chỉ số, thêm vào cuối thường xuyên
- VecDeque<T> — double-ended queue, efficient push/pop at both ends
VecDeque<T> — hàng đợi hai đầu, thêm/xóa hiệu quả ở cả đầu và cuối
- LinkedList<T> — rarely needed; Vec is usually faster due to cache locality
LinkedList<T> — hiếm khi dùng; Vec thường nhanh hơn do tính cục bộ bộ nhớ cache
- HashMap<K, V> — fast key-value lookup, order does not matter
HashMap<K, V> — tra cứu khóa-giá trị nhanh, thứ tự không quan trọng
- BTreeMap<K, V> — sorted key-value pairs, useful when iteration order matters
BTreeMap<K, V> — khóa-giá trị được sắp xếp, hữu ích khi cần lặp theo thứ tự
- HashSet<T> — fast O(1) membership testing, no duplicates
HashSet<T> — kiểm tra thành viên nhanh O(1), không trùng lặp
- BTreeSet<T> — sorted set, useful for ranges
BTreeSet<T> — tập hợp có thứ tự, hữu ích cho phạm vi
- String — owned UTF-8 text, prefer over Vec<u8> for text
String — văn bản UTF-8 thuộc sở hữu, thường thay thế Vec<u8> cho văn bản
Khi nghi ngờ, hãy bắt đầu với Vec và HashMap. Chúng bao phủ phần lớn các trường hợp sử dụng và có hiệu suất tốt trong thực tế.
Key Takeaways
Điểm Chính
- Vec<T> is a growable array stored on the heapVec<T> là mảng có thể mở rộng lưu trên heap
- String is a UTF-8 encoded, growable text typeString là kiểu văn bản mã hóa UTF-8 có thể mở rộng
- HashMap<K, V> stores key-value pairs with O(1) average lookupHashMap<K, V> lưu cặp khóa-giá trị với tra cứu trung bình O(1)
- Use .get() for safe access that returns Option instead of panickingDùng .get() để truy cập an toàn trả về Option thay vì panic
Practice
Test your understanding of this chapter
Which Vec method safely retrieves an element without panicking if the index is out of bounds?
Phương thức Vec nào truy xuất phần tử một cách an toàn mà không panic nếu chỉ số vượt giới hạn?
What traits must HashMap keys implement?
Các khóa của HashMap phải triển khai những trait nào?
A Rust String can be indexed by an integer to access individual characters, just like in Python or JavaScript.
Một String trong Rust có thể được lập chỉ mục bằng số nguyên để truy cập từng ký tự, giống như trong Python hay JavaScript.
Inserting a duplicate value into a HashSet is allowed and simply has no effect — the set remains unchanged.
Chèn một giá trị trùng lặp vào HashSet được phép và đơn giản là không có tác dụng — tập hợp vẫn không thay đổi.
Count word frequencies using the Entry API
Đếm tần suất từ bằng Entry API
let mut word_count: HashMap<&str, i32> = HashMap::new(); for word in text.split_whitespace() { let count = word_count.entry(word).(0); *count += 1; }