Menu
Coddy logo textTech

Указатели как значения карт

Часть раздела Логика и управление потоком путешествия по GO на Coddy — урок 27 из 68.

Хотя хранение структур напрямую в картах полезно, хранение указателей на структуры открывает мощную возможность: изменять исходные данные структуры напрямую через карту. Этот подход необходим, когда вам нужно обновить данные после того, как они были сохранены.

Когда вы сохраняете указатель на структуру в качестве значения карты (map), вы сохраняете адрес памяти этой структуры, а не её копию. Вот как можно объявить такую карту и работать с ней:

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},
}

Ключевое преимущество становится очевидным, когда вам нужно изменить данные. Поскольку вы работаете с указателями, изменения, внесенные через карту, влияют на исходную структуру:

// Обновите цену ноутбука напрямую через карту
products["laptop"].Price = 899.99
fmt.Println(products["laptop"].Price) // выводит: 899.99

Этот паттерн особенно полезен в приложениях, где требуется часто обновлять сохраненные данные, таких как системы учета инвентаря, профили пользователей или любые сценарии, в которых карта (map) служит основным хранилищем данных, а изменения должны сохраняться.

quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

challenge icon

Задание

Легко

Создайте простую систему управления запасами, которая демонстрирует возможности использования указателей на структуры в качестве значений карты (map). Эта задача показывает, как карты на основе указателей позволяют напрямую изменять сохраненные данные, делая вашу систему инвентаризации эффективной и отзывчивой к обновлениям.

Вы получите три входных параметра:

  • Строка, представляющая количество продуктов (например, "4")
  • Строка, содержащая данные о продуктах в формате: "name1:price1:quantity1,name2:price2:quantity2,name3:price3:quantity3" (например, "laptop:999.99:5,mouse:25.50:20,keyboard:75.00:15,monitor:299.99:8")
  • Строка, содержащая операции обновления в формате: "operation1:product1:value1,operation2:product2:value2", где операции могут быть либо "price", либо "quantity" (например, "price:laptop:899.99,quantity:mouse:25,price:keyboard:65.00")

Ваша задача:

  1. Определить структуру Product со следующими полями:
    • Price (float64) — цена продукта
    • Quantity (int) — количество товара на складе
  2. Создать карту (map), где ключами являются названия продуктов (строки), а значениями — указатели на структуры Product
  3. Разобрать данные о продуктах из второго входного параметра:
    • Разделить входную строку по запятым, чтобы получить записи об отдельных продуктах
    • Для каждой записи разделить ее по двоеточиям, чтобы отделить название, цену и количество
    • Преобразовать строку цены в float64, а строку количества — в целое число
    • Создать структуру Product и сохранить указатель на нее в карте
  4. Вывести начальный инвентарь с заголовком "Initial Inventory:"
  5. Показать каждый продукт в формате: "[name]: $[price] (Stock: [quantity])"
  6. Разобрать и применить операции обновления из третьего входного параметра:
    • Разделить входную строку по запятым, чтобы получить отдельные операции
    • Для каждой операции разделить ее по двоеточиям, чтобы получить тип операции, название продукта и новое значение
    • Обновить соответствующее поле напрямую через указатель в карте
    • Вывести каждое обновление в формате: "Updated [product]: [field] changed to [new_value]"
  7. Вывести обновленный инвентарь с заголовком "Updated Inventory:"
  8. Снова показать каждый продукт в том же формате, что и при начальном выводе
  9. Рассчитать и вывести общую стоимость инвентаря: "Total Inventory Value: $[total_value]"

Используйте пакет strconv для преобразования строк цены и количества в соответствующие числовые типы. При выводе форматируйте все цены до 2 знаков после запятой. Эта задача демонстрирует, как хранение указателей в картах позволяет изменять исходные данные структуры напрямую, делая обновления инвентаря немедленными и постоянными без необходимости повторного присвоения значений карте.

Шпаргалка

Карты могут хранить указатели на структуры, что позволяет напрямую изменять данные исходной структуры через карту:

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},
}

При использовании указателей в качестве значений карты изменения через карту влияют на исходную структуру:

// Обновление цены ноутбука напрямую через карту
products["laptop"].Price = 899.99
fmt.Println(products["laptop"].Price) // выводит: 899.99

Этот паттерн полезен для приложений, требующих частого обновления данных, таких как системы инвентаризации или профили пользователей, где карта служит основным хранилищем данных.

Попробуйте сами

package main

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

func main() {
	// Считать ввод
	var numProductsStr string
	var productDataStr string
	var operationsStr string
	
	fmt.Scanln(&numProductsStr)
	fmt.Scanln(&productDataStr)
	fmt.Scanln(&operationsStr)
	
	// TODO: Определите здесь структуру Product
	
	// TODO: Создайте карту (map) для хранения указателей на продукты
	
	// TODO: Создайте срез (slice) для сохранения порядка продуктов (для обеспечения согласованного вывода)
	
	// TODO: Разобрать данные о продуктах и заполнить карту
	// Не забудьте:
	// - Разделить productDataStr по запятым, чтобы получить отдельные записи
	// - Для каждой записи разделить по двоеточиям, чтобы получить название, цену, количество
	// - Преобразовать строки цены и количества в соответствующие типы
	// - Сохранить указатель на структуру Product в карте
	// - Добавить название продукта в срез порядка
	
	// TODO: Отобразить начальный инвентарь
	// Используйте срез порядка для последовательного перебора продуктов
	// Формат: "[name]: $[price] (Stock: [quantity])"
	
	// TODO: Разобрать и применить операции обновления
	// Не забудьте:
	// - Разделить operationsStr по запятым, чтобы получить отдельные операции
	// - Для каждой операции разделить по двоеточиям, чтобы получить тип, название, значение
	// - Обновить соответствующее поле напрямую через указатель в карте
	// - Вывести сообщение об обновлении для каждой операции
	
	// TODO: Отобразить обновленный инвентарь
	// Снова используйте срез порядка для согласованного вывода
	// Рассчитайте общую стоимость во время отображения
	
	// TODO: Рассчитать и отобразить общую стоимость инвентаря
	// Формат: "Total Inventory Value: $[total_value]"
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Логика и управление потоком