Map trong Go - Cách lưu trữ dữ liệu theo cặp! 📚
Chào mừng bạn đến với bài học về map trong Go! Giống như một cuốn từ điển, map giúp chúng ta lưu trữ thông tin theo cặp chìa khóa-giá trị. Trong bài học này, chúng ta sẽ tìm hiểu cách sử dụng map một cách hiệu quả.
Map là gì? 🤔
Giống như một cuốn từ điển:
- Có từ (key)
- Có nghĩa (value)
- Dễ dàng tra cứu
1. Khai báo map (Tạo từ điển mới) 📝
// Tạo từ điển rỗng
var scores map[string]int
// Tạo từ điển và thêm từ ngay
scores := map[string]int{
"Alice": 90,
"Bob": 85,
"Charlie": 95,
}
💡 Giải thích:
map[string]int
: Từ điển có từ là chữ, nghĩa là số{}
: Thêm các cặp từ-nghĩa ngay khi tạo
2. Tạo map với make (Tạo từ điển có kế hoạch) 🏗️
// Tạo từ điển rỗng
scores := make(map[string]int)
// Tạo từ điển có sẵn chỗ cho 10 từ
scores := make(map[string]int, 10)
💡 Giải thích:
make
: Tạo từ điển mới- Số 10: Dự kiến sẽ có 10 từ
Thao tác với Map 🎯
1. Thêm từ mới (Thêm cặp key-value)
scores["David"] = 88
💡 Giải thích:
"David"
: Từ mới88
: Nghĩa của từ
2. Tra từ (Truy cập giá trị)
// Cách 1: Tra đơn giản
score := scores["Alice"]
// Cách 2: Tra an toàn
score, exists := scores["Alice"]
if exists {
fmt.Printf("Điểm: %d\n", score)
}
💡 Giải thích:
- Cách 1: Nhanh nhưng không biết từ có tồn tại không
- Cách 2: An toàn hơn, biết được từ có tồn tại
3. Xóa từ (Xóa cặp key-value)
delete(scores, "Bob")
💡 Giải thích:
delete
: Xóa một từ và nghĩa của nó
4. Duyệt từ điển (Xem tất cả từ)
// Cách 1: Xem cả từ và nghĩa
for name, score := range scores {
fmt.Printf("%s: %d\n", name, score)
}
// Cách 2: Chỉ xem từ
for name := range scores {
fmt.Println(name)
}
💡 Giải thích:
range
: Duyệt qua từng cặp từ-nghĩa- Có thể bỏ qua nghĩa nếu không cần
Map với các kiểu dữ liệu khác nhau 🎨
1. Map với struct (Từ điển có nghĩa phức tạp)
type Person struct {
Name string
Age int
Email string
}
people := map[string]Person{
"john": Person{
Name: "John Doe",
Age: 30,
Email: "[email protected]",
},
}
💡 Giải thích:
- Nghĩa của từ là một hồ sơ
- Chứa nhiều thông tin khác nhau
2. Map với slice (Từ điển có nhiều nghĩa)
groups := map[string][]string{
"fruits": {"apple", "banana", "orange"},
"colors": {"red", "blue", "green"},
}
💡 Giải thích:
- Nghĩa của từ là một danh sách
- Có thể chứa nhiều giá trị
3. Map lồng nhau (Từ điển trong từ điển)
nestedMap := map[string]map[string]int{
"math": {
"algebra": 90,
"geometry": 85,
},
"science": {
"physics": 95,
"chemistry": 88,
},
}
💡 Giải thích:
- Nghĩa của từ là một từ điển khác
- Giúp tổ chức dữ liệu phức tạp
Ví dụ thực tế 🎯
1. Cache đơn giản (Bộ nhớ tạm)
type Cache struct {
data map[string]interface{}
}
func NewCache() *Cache {
return &Cache{
data: make(map[string]interface{}),
}
}
func (c *Cache) Set(key string, value interface{}) {
c.data[key] = value
}
func (c *Cache) Get(key string) (interface{}, bool) {
value, exists := c.data[key]
return value, exists
}
💡 Giải thích:
- Lưu tạm dữ liệu để truy cập nhanh
- Có thể lưu bất kỳ kiểu dữ liệu nào
2. Đếm tần suất (Đếm số lần xuất hiện)
func countFrequency(text string) map[rune]int {
freq := make(map[rune]int)
for _, char := range text {
freq[char]++
}
return freq
}
💡 Giải thích:
- Đếm số lần mỗi ký tự xuất hiện
- Dùng map để lưu kết quả
Best Practices (Cách sử dụng tốt) 🌟
1. Khởi tạo map đúng cách
// ✅ Tốt
scores := make(map[string]int)
// ❌ Không tốt
var scores map[string]int
scores["Alice"] = 90 // Lỗi!
💡 Lý do: Tránh lỗi khi thêm từ mới
2. Kiểm tra từ tồn tại
// ✅ Tốt
if score, exists := scores["Alice"]; exists {
fmt.Println(score)
}
// ❌ Không tốt
score := scores["Alice"] // Không biết từ có tồn tại không
💡 Lý do: Tránh lỗi khi tra từ không tồn tại
3. Chọn kiểu dữ liệu phù hợp
// ✅ Tốt
scores := make(map[string]int, 100) // Dự kiến 100 từ
// ❌ Không tốt
scores := make(map[string]int) // Không dự kiến số lượng
💡 Lý do: Tối ưu hiệu suất khi có nhiều từ
Những lỗi thường gặp và cách sửa 🔧
-
Lỗi: Thêm từ vào map chưa khởi tạo
// ❌ Sai
var scores map[string]int
scores["Alice"] = 90 // Lỗi!
// ✅ Đúng
scores := make(map[string]int)
scores["Alice"] = 90 -
Lỗi: Không kiểm tra từ tồn tại
// ❌ Sai
score := scores["Alice"] // Có thể là 0
// ✅ Đúng
if score, exists := scores["Alice"]; exists {
fmt.Println(score)
} -
Lỗi: Dùng map cho dữ liệu cần sắp xếp
// ❌ Sai
scores := make(map[string]int) // Không giữ thứ tự
// ✅ Đúng
type Score struct {
Name string
Value int
}
scores := []Score{} // Giữ được thứ tự
Tiếp theo 🎯
Trong bài học tiếp theo, chúng ta sẽ:
- Tìm hiểu về structs (cấu trúc dữ liệu)
- Học cách xử lý lỗi nâng cao
- Khám phá cách sử dụng goroutines
💡 Lời khuyên: Hãy thử tạo và sử dụng các map đơn giản để hiểu rõ hơn về cách chúng hoạt động!