Menu
CoddyTech

Con trỏ làm giá trị của map

Thuộc phần Logic và luồng điều khiển trong hành trình GO của Coddy. Bài học 27 trên 68.

Dù lưu trực tiếp các struct trong map rất hữu ích, lưu con trỏ đến struct còn mở ra một khả năng mạnh mẽ: chỉnh sửa trực tiếp dữ liệu của struct ban đầu thông qua map. Cách này rất cần thiết khi bạn cần cập nhật dữ liệu sau khi đã lưu.

Khi lưu một con trỏ đến struct làm giá trị trong map, bạn đang lưu địa chỉ bộ nhớ của struct chứ không phải bản sao của nó. Sau đây là cách khai báo và thao tác với map như vậy:

type Product struct {
    Price    float64
    Quantity int
}

products := map[string]*Product{
    "laptop": &Product{Price: 999.99, Quantity: 5},
    "mouse":  &Product{Price: 25.50, Quantity: 20},
}

Ưu điểm chính thể hiện rõ khi bạn cần sửa đổi dữ liệu. Vì bạn đang làm việc với các con trỏ, những thay đổi qua map sẽ ảnh hưởng đến struct gốc:

// Cập nhật giá của laptop trực tiếp qua map
products["laptop"].Price = 899.99
fmt.Println(products["laptop"].Price) // in ra: 899.99

Mẫu này đặc biệt hữu ích trong các ứng dụng cần thường xuyên cập nhật dữ liệu đã lưu, chẳng hạn như hệ thống quản lý hàng tồn kho, hồ sơ người dùng hoặc bất kỳ tình huống nào mà bản đồ đóng vai trò là kho dữ liệu chính và các thay đổi cần được lưu lại.

challenge icon

Thử thách

Dễ

Xây dựng một hệ thống quản lý hàng tồn kho đơn giản để minh họa sức mạnh của việc dùng con trỏ đến struct làm giá trị trong map. Thử thách này cho thấy map dùng con trỏ cho phép chỉnh sửa trực tiếp dữ liệu đã lưu, giúp hệ thống quản lý hàng tồn kho hoạt động hiệu quả và phản hồi nhanh khi có cập nhật.

Bạn sẽ nhận được ba đầu vào:

  • Một chuỗi biểu thị số lượng sản phẩm (ví dụ: "4")
  • Một chuỗi chứa dữ liệu sản phẩm theo định dạng: "name1:price1:quantity1,name2:price2:quantity2,name3:price3:quantity3" (ví dụ: "laptop:999.99:5,mouse:25.50:20,keyboard:75.00:15,monitor:299.99:8")
  • Một chuỗi chứa các thao tác cập nhật theo định dạng: "operation1:product1:value1,operation2:product2:value2", trong đó thao tác có thể là "price" hoặc "quantity" (ví dụ: "price:laptop:899.99,quantity:mouse:25,price:keyboard:65.00")

Nhiệm vụ của bạn là:

  1. Định nghĩa một struct Product với các trường sau:
    • Price (float64), giá của sản phẩm
    • Quantity (int), số lượng sản phẩm trong kho
  2. Tạo một map có khóa là tên sản phẩm (chuỗi) và giá trị là con trỏ đến các struct Product
  3. Phân tích dữ liệu sản phẩm từ đầu vào thứ hai:
    • Tách đầu vào theo dấu phẩy để lấy từng mục dữ liệu sản phẩm
    • Với mỗi mục, tách theo dấu hai chấm để phân chia tên, giá và số lượng
    • Chuyển chuỗi giá thành số thực float64 và chuỗi số lượng thành số nguyên
    • Tạo một struct Product và lưu con trỏ đến struct đó trong map
  4. Khi phân tích dữ liệu, giữ tên sản phẩm trong một slice riêng theo đúng thứ tự xuất hiện trong đầu vào. Khi duyệt map trong Go, các khóa sẽ xuất hiện theo thứ tự ngẫu nhiên, vì vậy slice giúp giữ nguyên thứ tự đầu vào cho mọi danh sách sản phẩm.
  5. Hiển thị hàng tồn kho ban đầu với tiêu đề "Initial Inventory:"
  6. Hiển thị từng sản phẩm theo định dạng: "[name]: $[price] (Stock: [quantity])"
  7. Phân tích và áp dụng các thao tác cập nhật từ đầu vào thứ ba:
    • Tách đầu vào theo dấu phẩy để lấy từng thao tác
    • Với mỗi thao tác, tách theo dấu hai chấm để lấy loại thao tác, tên sản phẩm và giá trị mới
    • Cập nhật trực tiếp trường thích hợp thông qua con trỏ trong map
    • In từng cập nhật theo định dạng: "Updated [product]: [field] changed to [new_value]"
  8. Hiển thị hàng tồn kho đã cập nhật với tiêu đề "Updated Inventory:"
  9. Hiển thị lại từng sản phẩm theo cùng định dạng như phần hiển thị ban đầu
  10. Tính và hiển thị tổng giá trị hàng tồn kho: "Total Inventory Value: $[total_value]"

Dùng package strconv để chuyển chuỗi giá và số lượng thành các kiểu số tương ứng. Định dạng tất cả giá với 2 chữ số thập phân khi hiển thị. Thử thách này minh họa cách lưu con trỏ trong map cho phép bạn chỉnh sửa trực tiếp dữ liệu struct ban đầu, giúp các cập nhật hàng tồn kho có hiệu lực ngay lập tức và được giữ lại mà không cần gán lại giá trị vào map.

Tự làm thử

package main

import (
	"fmt"
	"strconv"
	"strings"
)

func main() {
	// Đọc đầu vào
	var numProductsStr string
	var productDataStr string
	var operationsStr string
	
	fmt.Scanln(&numProductsStr)
	fmt.Scanln(&productDataStr)
	fmt.Scanln(&operationsStr)
	
	// TODO: Định nghĩa struct Product tại đây
	
	// TODO: Tạo map để lưu các con trỏ đến sản phẩm
	
	// TODO: Tạo slice để giữ thứ tự sản phẩm (đảm bảo đầu ra nhất quán)
	
	// TODO: Phân tích dữ liệu sản phẩm và thêm vào map
	// Nhớ thực hiện:
	// - Tách productDataStr theo dấu phẩy để lấy từng mục
	// - Với mỗi mục, tách theo dấu hai chấm để lấy tên, giá và số lượng
	// - Chuyển các chuỗi giá và số lượng sang kiểu dữ liệu phù hợp
	// - Lưu con trỏ đến struct Product vào map
	// - Thêm tên sản phẩm vào slice thứ tự
	
	// TODO: Hiển thị kho hàng ban đầu
	// Dùng lát cắt order để duyệt sản phẩm theo thứ tự nhất quán
	// Định dạng: "[name]: $[price] (Stock: [quantity])"
	
	// TODO: Phân tích và áp dụng các thao tác cập nhật
	// Nhớ thực hiện:
	// - Tách operationsStr theo dấu phẩy để lấy từng thao tác
	// - Với mỗi thao tác, tách theo dấu hai chấm để lấy loại, tên và giá trị
	// - Cập nhật trực tiếp trường tương ứng qua con trỏ trong map
	// - In ra thông báo cập nhật cho mỗi thao tác
	
	// TODO: Hiển thị kho hàng sau khi cập nhật
	// Tiếp tục dùng lát cắt order để đầu ra có thứ tự nhất quán
	// Tính tổng giá trị trong khi hiển thị
	
	// TODO: Tính và hiển thị tổng giá trị kho hàng
	// Định dạng: "Total Inventory Value: $[total_value]"
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Logic và luồng điều khiển

Tự luyện tập: Trình biên dịch Go online