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

HashMap trong Rust

HashMap lưu dữ liệu dưới dạng các cặp khóa-giá trị (key-value) — bạn tra cứu theo khóa chứ không theo vị trí như với mảng hay vector. Nếu bạn đã dùng dictionary trong Python hay dùng object làm map trong JavaScript, thì đây là cùng một ý tưởng.

use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alice", 30);
ages.insert("Bob", 25);
println!("{:?}", ages);
}

use std::collections::HashMap; ở đầu file đưa kiểu này vào phạm vi — khác với Vec và String, HashMap không có sẵn mặc định, nên dòng này là bắt buộc.

▶ Tự chạy thử
use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alice", 30);
match ages.get("Alice") {
Some(age) => println!("Alice {age} tuổi"),
None => println!("Không tìm thấy"),
}
}
▶ Tự chạy thử

.get() trả về một Option thay vì trả thẳng giá trị, vì khóa có thể không tồn tại. Chúng ta sẽ tìm hiểu kỹ về Option trong bài riêng của nó — tạm thời, match với Some/None là cách chuẩn để xử lý.

Insert lần nữa với cùng khóa sẽ ghi đè giá trị cũ:

use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alice", 30);
ages.insert("Alice", 31); // ghi đè 30
println!("{:?}", ages.get("Alice"));
}
▶ Tự chạy thử

Nếu bạn chỉ muốn thêm giá trị khi khóa chưa tồn tại, hãy dùng .entry():

use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alice", 30);
ages.entry("Alice").or_insert(99); // Alice đã có, nên dòng này không làm gì
ages.entry("Bob").or_insert(25); // Bob chưa có, nên dòng này thêm vào
println!("{:?}", ages);
}
▶ Tự chạy thử
use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alice", 30);
ages.insert("Bob", 25);
for (name, age) in &ages {
println!("{name} {age} tuổi");
}
}
▶ Tự chạy thử

Hãy dùng HashMap bất cứ khi nào bạn muốn tra cứu theo tên hay ID thay vì theo vị trí — đếm tần suất từ, ánh xạ tên người dùng sang dữ liệu người dùng, lưu cache kết quả theo khóa. Nếu thứ tự quan trọng hoặc bạn chỉ đang làm việc với một danh sách đơn giản, Vec sẽ phù hợp hơn.

Lưu ba cái tên và số điện thoại vào một HashMap. Sau đó tra cứu "Ben" (có trong danh bạ) và "Dana" (không có), rồi in một dòng thân thiện cho mỗi người. Gợi ý: duyệt qua ["Ben", "Dana"] và match trên .get(name).

Xem lời giải
use std::collections::HashMap;
fn main() {
let mut phone_book = HashMap::new();
phone_book.insert("Ana", "555-1234");
phone_book.insert("Ben", "555-9876");
phone_book.insert("Chen", "555-4321");
for name in ["Ben", "Dana"] {
match phone_book.get(name) {
Some(number) => println!("{name}: {number}"),
None => println!("{name}: không có trong danh bạ"),
}
}
}

Kết quả:

Ben: 555-9876
Dana: không có trong danh bạ
▶ Tự chạy thử

Duyệt qua những cái tên ta cần, thay vì duyệt qua map, còn cho ta một thứ tự cố định. Đó là mẹo tiện lợi mỗi khi bạn cần kết quả in ra có thể đoán trước từ một HashMap.

Bạn có các phiếu bầu ["đỏ", "xanh dương", "đỏ", "xanh lá", "xanh dương", "đỏ"]. Đếm xem mỗi màu được bao nhiêu phiếu, rồi in tổng của "đỏ", "xanh lá", "xanh dương" và "hồng" (màu không có phiếu nào). Gợi ý: counts.entry(color).or_insert(0) cho bạn số phiếu hiện tại của màu đó, bắt đầu từ 0. Cộng thêm một bằng *count += 1.

Xem lời giải
use std::collections::HashMap;
fn main() {
let votes = ["đỏ", "xanh dương", "đỏ", "xanh lá", "xanh dương", "đỏ"];
let mut counts = HashMap::new();
for color in votes {
let count = counts.entry(color).or_insert(0);
*count += 1;
}
for color in ["đỏ", "xanh lá", "xanh dương", "hồng"] {
match counts.get(color) {
Some(n) => println!("{color}: {n}"),
None => println!("{color}: 0"),
}
}
}

Kết quả:

đỏ: 3
xanh lá: 1
xanh dương: 2
hồng: 0
▶ Tự chạy thử

or_insert(0) trả về một tham chiếu khả biến (mutable reference) tới giá trị được lưu trong map, chứ không phải một bản sao. Dấu * trong *count += 1 nghĩa là “thay đổi con số mà nó trỏ tới”, nên chính map được cập nhật. Mẫu “entry, hoặc insert 0, rồi cộng 1” này là cách chuẩn để đếm trong Rust.

  • HashMap<K, V> lưu các cặp khóa-giá trị; đưa nó vào phạm vi bằng use std::collections::HashMap;.
  • .insert(key, value) thêm mới hoặc ghi đè; .get(key) tra cứu và trả về một Option.
  • .entry(key).or_insert(value) chỉ thêm khi khóa chưa có.
  • Thứ tự khi duyệt không được đảm bảo — đừng dựa vào nó.

Kiểm tra nhanh

1. Khác với Vec hay String, bạn cần gì để đưa HashMap vào phạm vi?

2. .entry(key).or_insert(value) làm gì?

3. Bạn có thể dựa vào thứ tự in ra của các phần tử khi duyệt qua một HashMap không?

Điểm: 0 / 3