Chuyển tới nội dung chính

📚 Vector: Danh Sách Có Thể Mở Rộng

Mục Tiêu Bài Học

Sau bài này, bạn sẽ:

  • ✅ Biết cách tạo và khởi tạo vectors
  • ✅ Thêm/xóa phần tử với push, pop, insert, remove
  • ✅ Truy cập phần tử an toàn với get()
  • ✅ Hiểu sự khác biệt giữa Vector và Array

🤔 Vấn Đề Với Arrays

Arrays rất tốt, nhưng có giới hạn lớn: Độ dài cố định!

fn main() {
let mut arr = [1, 2, 3]; // Cố định 3 phần tử

// ❌ Không thể thêm phần tử thứ 4!
// arr.push(4); // Không có method này

// ❌ Không thể xóa phần tử!
// arr.remove(0); // Không có method này
}

Giải pháp: Dùng Vector! 🚀


📝 Vector Là Gì?

Vector (Vec<T>) là một collection động:

  • Có thể thêm/xóa phần tử
  • Độ dài thay đổi được
  • Cùng kiểu dữ liệu (giống array)
  • Lưu trên heap (linh hoạt hơn stack)
Ẩn Dụ

Hãy tưởng tượng vector như một kho đồ bảo hộ linh hoạt:

  • 📦 Ban đầu: 3 mũ bảo hiểm
  • Thêm: Mua thêm 2 mũ → Giờ có 5 mũ
  • Xóa: Cho đi 1 mũ → Còn 4 mũ
  • 🔄 Linh hoạt: Kho tự động mở rộng/thu nhỏ!

Khác với array (tủ cố định), vector như kho động thay đổi theo nhu cầu! 🛡️


📝 Tạo Vector

Cách 1: Vec::new()

fn main() {
let mut vec: Vec<i32> = Vec::new(); // Vector rỗng
println!("Vector: {:?}", vec);
}

Kết quả:

Vector: []

Giải thích:

  • Vec::new() → Tạo vector rỗng
  • Vec<i32> → Vector chứa kiểu i32
  • mut → Cần mut để thêm/xóa phần tử

Cách 2: vec! Macro

fn main() {
let vec = vec![10, 20, 30, 40, 50];
println!("Vector: {:?}", vec);
}

Kết quả:

Vector: [10, 20, 30, 40, 50]

Giải thích:

  • vec![...] → Macro tạo vector với giá trị sẵn
  • Rust tự suy luận kiểu (type inference)

Cách 3: Giá Trị Giống Nhau

fn main() {
let zeros = vec![0; 5]; // 5 phần tử giá trị 0
println!("Zeros: {:?}", zeros);
}

Kết quả:

Zeros: [0, 0, 0, 0, 0]

➕ Thêm Phần Tử: push()

Dùng .push() để thêm phần tử vào cuối vector:

fn main() {
let mut danh_sach = Vec::new();

danh_sach.push(10);
danh_sach.push(20);
danh_sach.push(30);

println!("Danh sách: {:?}", danh_sach);
}

Kết quả:

Danh sách: [10, 20, 30]

Ví Dụ Thực Tế: Thêm Điểm

fn main() {
let mut diem = vec![];

println!("Nhập điểm 5 môn:");
diem.push(85);
diem.push(92);
diem.push(78);
diem.push(95);
diem.push(88);

println!("\n📊 Điểm các môn: {:?}", diem);
}

Kết quả:

Nhập điểm 5 môn:

📊 Điểm các môn: [85, 92, 78, 95, 88]

➖ Xóa Phần Tử Cuối: pop()

Dùng .pop() để xóa và trả về phần tử cuối:

fn main() {
let mut stack = vec![10, 20, 30];

println!("Stack ban đầu: {:?}", stack);

let last = stack.pop(); // Xóa 30
println!("Lấy ra: {:?}", last);
println!("Stack hiện tại: {:?}", stack);

let last = stack.pop(); // Xóa 20
println!("Lấy ra: {:?}", last);
println!("Stack hiện tại: {:?}", stack);
}

Kết quả:

Stack ban đầu: [10, 20, 30]
Lấy ra: Some(30)
Stack hiện tại: [10, 20]
Lấy ra: Some(20)
Stack hiện tại: [10]

Giải thích:

  • .pop() trả về Option<T>
  • Some(giá_trị) nếu có phần tử
  • None nếu vector rỗng
fn main() {
let mut vec = vec![];
let result = vec.pop();

match result {
Some(val) => println!("Lấy ra: {}", val),
None => println!("Vector rỗng!"),
}
}

Kết quả:

Vector rỗng!

🔍 Truy Cập Phần Tử

Cách 1: Dùng Index []

fn main() {
let vec = vec![10, 20, 30, 40, 50];

println!("Phần tử đầu: {}", vec[0]);
println!("Phần tử cuối: {}", vec[4]);
}

Kết quả:

Phần tử đầu: 10
Phần tử cuối: 50
Cảnh Báo

Truy cập index không tồn tại → Panic!

let vec = vec![1, 2, 3];
// ❌ Panic! Index 10 không tồn tại
// println!("{}", vec[10]);

Cách 2: Dùng get() - An Toàn Hơn

fn main() {
let vec = vec![10, 20, 30];

match vec.get(1) {
Some(val) => println!("Giá trị tại index 1: {}", val),
None => println!("Index không tồn tại"),
}

match vec.get(10) {
Some(val) => println!("Giá trị tại index 10: {}", val),
None => println!("Index 10 không tồn tại"),
}
}

Kết quả:

Giá trị tại index 1: 20
Index 10 không tồn tại
Nên Dùng Cái Nào?
MethodKhi Nào DùngKhi Index Không Tồn Tại
vec[i]Chắc chắn index hợp lệ❌ Panic (crash)
vec.get(i)Không chắc index hợp lệ✅ Trả về None
// ✅ Dùng [] khi chắc chắn
for i in 0..vec.len() {
println!("{}", vec[i]); // An toàn
}

// ✅ Dùng get() khi không chắc
let user_input = 100; // Từ người dùng
match vec.get(user_input) {
Some(val) => println!("{}", val),
None => println!("Không tồn tại"),
}

🔧 Các Methods Hữu Ích

len() - Độ Dài

fn main() {
let vec = vec![1, 2, 3, 4, 5];
println!("Độ dài: {}", vec.len());
}

Kết quả:

Độ dài: 5

is_empty() - Kiểm Tra Rỗng

fn main() {
let vec1 = vec![];
let vec2 = vec![1, 2, 3];

println!("vec1 rỗng? {}", vec1.is_empty());
println!("vec2 rỗng? {}", vec2.is_empty());
}

Kết quả:

vec1 rỗng? true
vec2 rỗng? false

clear() - Xóa Tất Cả

fn main() {
let mut vec = vec![1, 2, 3, 4, 5];

println!("Trước: {:?}", vec);
vec.clear();
println!("Sau: {:?}", vec);
}

Kết quả:

Trước: [1, 2, 3, 4, 5]
Sau: []

insert() - Chèn Vào Vị Trí

fn main() {
let mut vec = vec![1, 2, 4, 5];

println!("Trước: {:?}", vec);
vec.insert(2, 3); // Chèn 3 vào index 2
println!("Sau: {:?}", vec);
}

Kết quả:

Trước: [1, 2, 4, 5]
Sau: [1, 2, 3, 4, 5]

remove() - Xóa Tại Vị Trí

fn main() {
let mut vec = vec![10, 20, 30, 40, 50];

println!("Trước: {:?}", vec);
let removed = vec.remove(2); // Xóa index 2
println!("Đã xóa: {}", removed);
println!("Sau: {:?}", vec);
}

Kết quả:

Trước: [10, 20, 30, 40, 50]
Đã xóa: 30
Sau: [10, 20, 40, 50]

contains() - Kiểm Tra Tồn Tại

fn main() {
let vec = vec![10, 20, 30, 40];

println!("Có 30? {}", vec.contains(&30));
println!("Có 50? {}", vec.contains(&50));
}

Kết quả:

Có 30? true
Có 50? false

🔄 Lặp Qua Vector

Cách 1: For Loop

fn main() {
let vec = vec![10, 20, 30, 40];

for val in &vec {
println!("{}", val);
}
}

Kết quả:

10
20
30
40

Cách 2: Với Index

fn main() {
let vec = vec!["Táo", "Cam", "Chuối"];

for (i, fruit) in vec.iter().enumerate() {
println!("{}. {}", i + 1, fruit);
}
}

Kết quả:

1. Táo
2. Cam
3. Chuối

Cách 3: Thay Đổi Giá Trị

fn main() {
let mut vec = vec![1, 2, 3, 4, 5];

println!("Trước: {:?}", vec);

for val in &mut vec {
*val *= 2; // Nhân đôi
}

println!("Sau: {:?}", vec);
}

Kết quả:

Trước: [1, 2, 3, 4, 5]
Sau: [2, 4, 6, 8, 10]

🎮 Ví Dụ Thực Tế: Quản Lý Danh Sách Việc

fn main() {
let mut todo_list: Vec<String> = Vec::new();

// Thêm việc cần làm
todo_list.push(String::from("Học Rust"));
todo_list.push(String::from("Làm bài tập"));
todo_list.push(String::from("Đọc tài liệu"));

println!("📝 Danh sách việc cần làm:");
for (i, task) in todo_list.iter().enumerate() {
println!("{}. {}", i + 1, task);
}

// Hoàn thành việc đầu tiên
if !todo_list.is_empty() {
let done = todo_list.remove(0);
println!("\n✅ Đã hoàn thành: {}", done);
}

println!("\n📝 Còn lại:");
for (i, task) in todo_list.iter().enumerate() {
println!("{}. {}", i + 1, task);
}
}

Kết quả:

📝 Danh sách việc cần làm:
1. Học Rust
2. Làm bài tập
3. Đọc tài liệu

✅ Đã hoàn thành: Học Rust

📝 Còn lại:
1. Làm bài tập
2. Đọc tài liệu

🔍 Ví Dụ: Lọc Số Chẵn

fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let mut even_numbers = Vec::new();

for &num in &numbers {
if num % 2 == 0 {
even_numbers.push(num);
}
}

println!("Số ban đầu: {:?}", numbers);
println!("Số chẵn: {:?}", even_numbers);
}

Kết quả:

Số ban đầu: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Số chẵn: [2, 4, 6, 8, 10]

📊 Ví Dụ: Tính Thống Kê

fn main() {
let diem = vec![85, 92, 78, 95, 88, 76, 90];

// Tính tổng
let mut tong = 0;
for &d in &diem {
tong += d;
}

// Trung bình
let trung_binh = tong as f64 / diem.len() as f64;

// Tìm max/min
let mut max = diem[0];
let mut min = diem[0];
for &d in &diem {
if d > max {
max = d;
}
if d < min {
min = d;
}
}

println!("📊 Thống kê điểm:");
println!("Số lượng: {}", diem.len());
println!("Tổng: {}", tong);
println!("Trung bình: {:.2}", trung_binh);
println!("Cao nhất: {}", max);
println!("Thấp nhất: {}", min);
}

Kết quả:

📊 Thống kê điểm:
Số lượng: 7
Tổng: 604
Trung bình: 86.29
Cao nhất: 95
Thấp nhất: 76

⚠️ Lỗi Thường Gặp

1. Quên Mut

fn main() {
let vec = Vec::new(); // ❌ Không mut
// vec.push(1); // Lỗi!

let mut vec = Vec::new(); // ✅ Đúng
vec.push(1);
}

2. Sử Dụng Sau Khi Move

fn main() {
let vec = vec![1, 2, 3];

for item in vec { // ❌ vec bị move
println!("{}", item);
}

// println!("{:?}", vec); // ❌ Lỗi!

// ✅ Đúng - Dùng reference
let vec = vec![1, 2, 3];
for item in &vec {
println!("{}", item);
}
println!("{:?}", vec); // ✅ OK
}

3. Index Ngoài Phạm Vi

fn main() {
let vec = vec![1, 2, 3];

// ❌ Panic!
// println!("{}", vec[10]);

// ✅ An toàn
match vec.get(10) {
Some(val) => println!("{}", val),
None => println!("Không tồn tại"),
}
}

💪 Bài Tập Thực Hành

Bài 1: Thêm và Xóa

Tạo vector, thêm 5 số, sau đó xóa 3 số cuối.

fn main() {
let mut numbers = Vec::new();

// Viết code của bạn ở đây
}
💡 Xem Đáp Án
fn main() {
let mut numbers = Vec::new();

// Thêm 5 số
for i in 1..=5 {
numbers.push(i);
}
println!("Sau khi thêm: {:?}", numbers);

// Xóa 3 số cuối
for _ in 0..3 {
numbers.pop();
}
println!("Sau khi xóa: {:?}", numbers);
}

Kết quả:

Sau khi thêm: [1, 2, 3, 4, 5]
Sau khi xóa: [1, 2]

Bài 2: Lọc Số Lớn Hơn 50

Từ vector cho trước, tạo vector mới chỉ chứa số > 50.

fn main() {
let numbers = vec![25, 60, 45, 80, 30, 90, 55];

// Viết code của bạn ở đây
}
💡 Xem Đáp Án
fn main() {
let numbers = vec![25, 60, 45, 80, 30, 90, 55];
let mut large_numbers = Vec::new();

for &num in &numbers {
if num > 50 {
large_numbers.push(num);
}
}

println!("Số ban đầu: {:?}", numbers);
println!("Số > 50: {:?}", large_numbers);
}

Kết quả:

Số ban đầu: [25, 60, 45, 80, 30, 90, 55]
Số > 50: [60, 80, 90, 55]

Bài 3: Ghép Hai Vector

Ghép hai vectors thành một.

fn main() {
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];

// Viết code của bạn ở đây
}
💡 Xem Đáp Án
fn main() {
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
let mut combined = Vec::new();

for &val in &vec1 {
combined.push(val);
}
for &val in &vec2 {
combined.push(val);
}

println!("Vec 1: {:?}", vec1);
println!("Vec 2: {:?}", vec2);
println!("Ghép: {:?}", combined);
}

Hoặc dùng extend:

fn main() {
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
let mut combined = vec1.clone();
combined.extend(vec2);

println!("Ghép: {:?}", combined);
}

Kết quả:

Vec 1: [1, 2, 3]
Vec 2: [4, 5, 6]
Ghép: [1, 2, 3, 4, 5, 6]

📝 Tóm Tắt

MethodMô TảVí Dụ
Vec::new()Tạo vector rỗnglet v: Vec<i32> = Vec::new();
vec![...]Tạo với giá trịlet v = vec![1, 2, 3];
.push(val)Thêm cuốiv.push(10);
.pop()Xóa cuốiv.pop();
.insert(i, val)Chèn vào vị trív.insert(1, 5);
.remove(i)Xóa tại vị trív.remove(2);
.len()Độ dàiv.len()
.is_empty()Kiểm tra rỗngv.is_empty()
.clear()Xóa tất cảv.clear();
.contains(&val)Kiểm tra tồn tạiv.contains(&5)
.get(i)Truy cập an toànv.get(10)

🆚 Vector vs Array

Đặc ĐiểmArrayVector
Độ dàiCố địnhThay đổi được
Khai báo[i32; 5]Vec<i32>
Khởi tạo[1, 2, 3]vec![1, 2, 3]
Thêm/xóa❌ Không✅ Có
Lưu trữStackHeap
Hiệu suấtNhanh hơnChậm hơn một chút
Linh hoạtThấpCao
Khi Nào Dùng Cái Nào?

Dùng Array khi:

  • ✅ Biết trước số lượng cố định
  • ✅ Không cần thêm/xóa
  • ✅ Cần hiệu suất tối đa

Dùng Vector khi:

  • ✅ Không biết trước số lượng
  • ✅ Cần thêm/xóa thường xuyên
  • ✅ Cần tính linh hoạt

Trong thực tế: Vector được dùng nhiều hơn vì linh hoạt!


🎯 Bước Tiếp Theo

Bạn đã biết Arrays và Vectors rồi! Nhưng nếu muốn gộp nhiều kiểu dữ liệu khác nhau, thì sao?

Bài tiếp theo, chúng ta sẽ học Tuple - gộp nhiều giá trị khác kiểu lại với nhau! 🎁

➡️ Tiếp theo: Tuple: Gói Nhiều Giá Trị Lại

Loading comments...