Skip to main content

📋 Menu Nhà Hàng - Maps

Chào mừng đến với bài học về Maps - hệ thống menu và tra cứu giá trong Bếp Á!

🎯 Món Ăn Hôm Nay

Tưởng tượng bạn là quản lý nhà hàng với bảng giá:

  • Phở Bò → 50,000 VND
  • Bún Chả → 45,000 VND
  • Gỏi Cuốn → 30,000 VND

Khách hỏi "Phở bao nhiêu?" → Bạn tra menu → Trả lời "50,000 VND"

Đó chính là Map - bảng tra cứu key-value!

🥘 Maps Là Gì?

Map = Menu nhà hàng (tra cứu món → giá)

// Menu: Tên món → Giá tiền
menu := map[string]int{
"Phở Bò": 50000,
"Bún Chả": 45000,
"Gỏi Cuốn": 30000,
}

// Tra cứu giá
gia := menu["Phở Bò"]
fmt.Println(gia) // 50000

🍜 Ẩn Dụ Nhà Hàng:

  • Key (Tên món) = Món khách gọi
  • Value (Giá) = Giá tiền phải trả
  • map[key] = Tra menu

👨‍🍳 Câu Chuyện Trong Bếp

Sáng nay, quán phở của anh Hùng đông khách:

Tình huống 1: Khách hỏi giá

menu := map[string]int{
"Phở Bò": 50000,
"Phở Gà": 45000,
"Bún Chả": 45000,
}

// Khách hỏi: "Phở Bò bao nhiêu?"
gia, coMon := menu["Phở Bò"]
if coMon {
fmt.Printf("Phở Bò: %d VND\n", gia)
} else {
fmt.Println("❌ Hết món rồi ạ!")
}

Tình huống 2: Cập nhật menu

// Thêm món mới
menu["Nem Rán"] = 25000

// Tăng giá do nguyên liệu đắt
menu["Phở Bò"] = 55000

// Xóa món hết nguyên liệu
delete(menu, "Bún Chả")

🎉 Kết quả: Map giúp quản lý menu dễ dàng!

📝 Công Thức Nấu (Code Examples)

Ví Dụ 1: Tạo Menu Cơ Bản

package main

import "fmt"

func main() {
// Cách 1: Tạo menu trống
menu := make(map[string]int)
menu["Phở Bò"] = 50000
menu["Bún Chả"] = 45000

// Cách 2: Tạo menu có sẵn món
menuDayDu := map[string]int{
"Phở Bò": 50000,
"Phở Gà": 45000,
"Bún Chả": 45000,
"Gỏi Cuốn": 30000,
"Nem Rán": 25000,
}

fmt.Println("📋 MENU NHÀ HÀNG:")
for mon, gia := range menuDayDu {
fmt.Printf("%-15s: %d VND\n", mon, gia)
}
}

Ví Dụ 2: Tra Cứu An Toàn

func main() {
menu := map[string]int{
"Phở Bò": 50000,
"Bún Chả": 45000,
}

// Khách gọi món
monKhachGoi := "Cơm Tấm"

// Tra menu an toàn
gia, coMon := menu[monKhachGoi]

if coMon {
fmt.Printf("✅ %s: %d VND\n", monKhachGoi, gia)
} else {
fmt.Printf("❌ Xin lỗi, không có %s\n", monKhachGoi)
fmt.Println("\n📋 Menu hiện có:")
for mon := range menu {
fmt.Println("- " + mon)
}
}
}

Ví Dụ 3: Map Với Struct - Thông Tin Chi Tiết

type MonAn struct {
Ten string
Gia int
ThoiGianNau int // phút
NguyenLieu []string
}

func main() {
menu := map[string]MonAn{
"PHO_BO": {
Ten: "Phở Bò",
Gia: 50000,
ThoiGianNau: 10,
NguyenLieu: []string{"Thịt bò", "Bánh phở", "Nước dùng"},
},
"BUN_CHA": {
Ten: "Bún Chả",
Gia: 45000,
ThoiGianNau: 15,
NguyenLieu: []string{"Thịt nướng", "Bún", "Nước mắm"},
},
}

// In thông tin món
mon := menu["PHO_BO"]
fmt.Printf("🍜 %s\n", mon.Ten)
fmt.Printf("💰 Giá: %d VND\n", mon.Gia)
fmt.Printf("⏱️ Thời gian: %d phút\n", mon.ThoiGianNau)
fmt.Println("🥘 Nguyên liệu:")
for _, nl := range mon.NguyenLieu {
fmt.Println(" - " + nl)
}
}

Ví Dụ 4: Đếm Món Đã Bán

func main() {
// Thống kê món đã bán
daBan := map[string]int{}

// Khách gọi món (giả lập)
orderList := []string{"Phở Bò", "Bún Chả", "Phở Bò", "Gỏi Cuốn", "Phở Bò"}

for _, mon := range orderList {
daBan[mon]++ // Tăng số lượng
}

fmt.Println("📊 THỐNG KÊ MÓN ĐÃ BÁN:")
for mon, soLuong := range daBan {
fmt.Printf("%-15s: %d tô/phần\n", mon, soLuong)
}
}

Ví Dụ 5: Map Lồng Nhau - Menu Theo Loại

func main() {
menuTheoLoai := map[string]map[string]int{
"Món chính": {
"Phở Bò": 50000,
"Bún Chả": 45000,
"Cơm Tấm": 40000,
},
"Món phụ": {
"Gỏi Cuốn": 30000,
"Nem Rán": 25000,
"Chả Giò": 28000,
},
"Nước uống": {
"Trà Đá": 5000,
"Nước Chanh": 15000,
"Sinh Tố": 25000,
},
}

fmt.Println("📋 MENU THEO LOẠI:\n")
for loai, danhSach := range menuTheoLoai {
fmt.Printf("=== %s ===\n", loai)
for mon, gia := range danhSach {
fmt.Printf("%-15s: %d VND\n", mon, gia)
}
fmt.Println()
}
}

🔥 Thực Hành Trong Bếp

Bài Tập 1: Hệ Thống Đặt Món

package main

import "fmt"

func main() {
menu := map[string]int{
"Phở Bò": 50000,
"Bún Chả": 45000,
"Gỏi Cuốn": 30000,
}

// Đơn hàng khách
donHang := map[string]int{
"Phở Bò": 2,
"Gỏi Cuốn": 3,
}

fmt.Println("🧾 HÓA ĐƠN:\n")
tongTien := 0

for mon, soLuong := range donHang {
gia := menu[mon]
thanhTien := gia * soLuong
tongTien += thanhTien

fmt.Printf("%-15s x%d = %d VND\n", mon, soLuong, thanhTien)
}

fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━")
fmt.Printf("TỔNG CỘNG: %d VND\n", tongTien)
}

Bài Tập 2: Giảm Giá Theo Khách Hàng

func main() {
menu := map[string]int{
"Phở Bò": 50000,
"Bún Chả": 45000,
}

// Mức giảm giá theo loại khách
giamGia := map[string]int{
"VIP": 20, // 20%
"ThanhVien": 10, // 10%
"ThuongXuyen": 5, // 5%
}

loaiKhach := "VIP"
mon := "Phở Bò"
giaGoc := menu[mon]

phanTramGiam := giamGia[loaiKhach]
soTienGiam := giaGoc * phanTramGiam / 100
giaSauGiam := giaGoc - soTienGiam

fmt.Printf("🍜 Món: %s\n", mon)
fmt.Printf("👤 Loại khách: %s\n", loaiKhach)
fmt.Printf("💵 Giá gốc: %d VND\n", giaGoc)
fmt.Printf("🎉 Giảm %d%%: -%d VND\n", phanTramGiam, soTienGiam)
fmt.Printf("💰 Thanh toán: %d VND\n", giaSauGiam)
}

Bài Tập 3: Quản Lý Tồn Kho

func main() {
// Số lượng tồn kho
tonKho := map[string]int{
"Phở Bò": 20,
"Bún Chả": 15,
"Gỏi Cuốn": 30,
}

// Khách đặt món
monDat := "Phở Bò"
soLuongDat := 5

fmt.Printf("📦 Tồn kho %s: %d phần\n", monDat, tonKho[monDat])
fmt.Printf("🛒 Khách đặt: %d phần\n", soLuongDat)

if tonKho[monDat] >= soLuongDat {
tonKho[monDat] -= soLuongDat
fmt.Printf("✅ Đặt thành công!\n")
fmt.Printf("📦 Còn lại: %d phần\n", tonKho[monDat])
} else {
fmt.Printf("❌ Không đủ hàng!\n")
fmt.Printf("📦 Chỉ còn: %d phần\n", tonKho[monDat])
}
}

⚠️ Những Lỗi Đầu Bếp Thường Gặp

Lỗi 1: Map Chưa Khởi Tạo

// ❌ SAI: Map nil không thể gán
func main() {
var menu map[string]int
menu["Phở"] = 50000 // Panic!
}

// ✅ ĐÚNG: Khởi tạo trước khi dùng
func main() {
menu := make(map[string]int)
menu["Phở"] = 50000 // OK
}

Lỗi 2: Không Kiểm Tra Key Tồn Tại

// ❌ SAI: Không biết món có hay không
func main() {
menu := map[string]int{"Phở": 50000}
gia := menu["Bún"]
fmt.Println(gia) // 0 - Không biết có món hay không
}

// ✅ ĐÚNG: Kiểm tra trước khi dùng
func main() {
menu := map[string]int{"Phở": 50000}
if gia, ok := menu["Bún"]; ok {
fmt.Println(gia)
} else {
fmt.Println("❌ Không có món này!")
}
}

Lỗi 3: Map Không Giữ Thứ Tự

// ❌ SAI: Mong đợi thứ tự cố định
func main() {
menu := map[string]int{
"Phở": 50000,
"Bún": 45000,
"Gỏi": 30000,
}

// Thứ tự in ra ngẫu nhiên mỗi lần chạy!
for mon := range menu {
fmt.Println(mon)
}
}

// ✅ ĐÚNG: Dùng slice để giữ thứ tự
func main() {
menu := map[string]int{
"Phở": 50000,
"Bún": 45000,
"Gỏi": 30000,
}

// Danh sách thứ tự
thuTu := []string{"Phở", "Bún", "Gỏi"}

for _, mon := range thuTu {
fmt.Printf("%s: %d VND\n", mon, menu[mon])
}
}

Lỗi 4: Thay Đổi Map Khi Duyệt

// ❌ SAI: Thay đổi map khi đang duyệt
func main() {
menu := map[string]int{"Phở": 50000}

for mon := range menu {
delete(menu, mon) // Nguy hiểm!
menu["Bún"] = 45000 // Có thể lỗi!
}
}

// ✅ ĐÚNG: Lưu keys trước, rồi mới thay đổi
func main() {
menu := map[string]int{"Phở": 50000}

keys := []string{}
for mon := range menu {
keys = append(keys, mon)
}

for _, mon := range keys {
delete(menu, mon)
}

menu["Bún"] = 45000 // An toàn
}

💡 Bí Quyết Của Đầu Bếp

  1. Luôn khởi tạo map: Dùng make() hoặc map[K]V{}
  2. Kiểm tra key tồn tại: Dùng value, ok := map[key]
  3. Map không có thứ tự: Dùng slice riêng nếu cần thứ tự
  4. Capacity cho map lớn: make(map[K]V, size) khi biết trước
  5. Tránh thay đổi khi duyệt: Lưu keys ra riêng trước

🎓 Bạn Đã Học Được

  • ✅ Map = Bảng tra cứu key → value (Menu → Giá)
  • ✅ make() = Tạo map mới
  • ✅ map[key] = value = Thêm/sửa phần tử
  • ✅ value, ok := map[key] = Tra cứu an toàn
  • ✅ delete(map, key) = Xóa phần tử
  • ✅ for key, value := range map = Duyệt map

🍜 Món Tiếp Theo

Menu đã có! Giờ cần đơn gọi món cho khách:

👉 Đơn Gọi Món - Structs


💡 Lời Khuyên Cuối: Map giống menu nhà hàng - càng rõ ràng, càng tra nhanh! Thực hành nhiều với map để quản lý dữ liệu hiệu quả như đầu bếp chuyên nghiệp!