Указатели как значения карт
Часть раздела Логика и управление потоком путешествия по 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) служит основным хранилищем данных, а изменения должны сохраняться.
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Задание
ЛегкоСоздайте простую систему управления запасами, которая демонстрирует возможности использования указателей на структуры в качестве значений карты (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")
Ваша задача:
- Определить структуру
Productсо следующими полями:Price(float64) — цена продуктаQuantity(int) — количество товара на складе
- Создать карту (map), где ключами являются названия продуктов (строки), а значениями — указатели на структуры
Product - Разобрать данные о продуктах из второго входного параметра:
- Разделить входную строку по запятым, чтобы получить записи об отдельных продуктах
- Для каждой записи разделить ее по двоеточиям, чтобы отделить название, цену и количество
- Преобразовать строку цены в float64, а строку количества — в целое число
- Создать структуру
Productи сохранить указатель на нее в карте
- Вывести начальный инвентарь с заголовком
"Initial Inventory:" - Показать каждый продукт в формате:
"[name]: $[price] (Stock: [quantity])" - Разобрать и применить операции обновления из третьего входного параметра:
- Разделить входную строку по запятым, чтобы получить отдельные операции
- Для каждой операции разделить ее по двоеточиям, чтобы получить тип операции, название продукта и новое значение
- Обновить соответствующее поле напрямую через указатель в карте
- Вывести каждое обновление в формате:
"Updated [product]: [field] changed to [new_value]"
- Вывести обновленный инвентарь с заголовком
"Updated Inventory:" - Снова показать каждый продукт в том же формате, что и при начальном выводе
- Рассчитать и вывести общую стоимость инвентаря:
"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]"
}В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Логика и управление потоком
1Продвинутое управление потоком выполнения
Switch с использованием `fallthrough`Выход из вложенных цикловПродолжение конкретного циклаОператор `goto`Итоги: Продвинутое управление циклами4Проект: Простой список задач
Настройка проектаДобавление задачи2Структуры и методы
Определение методов для структурПолучатели по значениюПолучатели по указателюВыбор типа получателяМетоды против функцийИтоги: поведение структур5Карты: подробный разбор
Карты структурУказатели как значения картПроверка карт на nilСравнение картИтоги: счетчик частоты слов3Интерфейсы (Основы)
Что такое интерфейс?Определение интерфейсаРеализация интерфейсаИспользование интерфейсных типовПустой интерфейсУтверждение типаПереключатель типовИтоги: Фигуры и поведение