Ponteiros como Valores de Map
Parte da seção Lógica & Fluxo do Journey de GO da Coddy. Lição 27 de 68.
Embora armazenar structs diretamente em mapas seja útil, armazenar ponteiros para structs desbloqueia uma poderosa capacidade: a possibilidade de modificar diretamente os dados da struct original por meio do mapa. Essa abordagem é essencial quando você precisa atualizar seus dados depois que eles foram armazenados.
Quando você armazena um ponteiro para uma struct como valor de um mapa, está armazenando o endereço de memória da struct, não uma cópia dela. Veja como declarar e trabalhar com esse tipo de mapa:
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},
}A principal vantagem fica clara quando você precisa modificar os dados. Como você está trabalhando com ponteiros, as alterações feitas por meio do mapa afetam a struct original:
// Atualize o preço do laptop diretamente através do map
products["laptop"].Price = 899.99
fmt.Println(products["laptop"].Price) // imprime: 899.99Esse padrão é particularmente valioso em aplicações nas quais você precisa atualizar frequentemente os dados armazenados, como sistemas de inventário, perfis de usuário ou qualquer cenário em que o mapa sirva como seu armazenamento de dados principal e as modificações precisem persistir.
Desafio
FácilCrie um sistema simples de gerenciamento de estoque que demonstre o poder de usar ponteiros para structs como valores de um mapa. Este desafio mostra como mapas baseados em ponteiros permitem a modificação direta dos dados armazenados, tornando seu sistema de estoque eficiente e responsivo às atualizações.
Você receberá três entradas:
- Uma string que representa o número de produtos (por exemplo,
"4") - Uma string contendo os dados dos produtos no formato:
"name1:price1:quantity1,name2:price2:quantity2,name3:price3:quantity3"(por exemplo,"laptop:999.99:5,mouse:25.50:20,keyboard:75.00:15,monitor:299.99:8") - Uma string contendo operações de atualização no formato:
"operation1:product1:value1,operation2:product2:value2", em que as operações são"price"ou"quantity"(por exemplo,"price:laptop:899.99,quantity:mouse:25,price:keyboard:65.00")
Sua tarefa é:
- Definir uma struct
Productcom os seguintes campos:Price(float64) - o preço do produtoQuantity(int) - a quantidade do produto em estoque
- Criar um mapa em que as chaves sejam os nomes dos produtos (strings) e os valores sejam ponteiros para structs
Product - Analisar os dados dos produtos a partir da segunda entrada:
- Dividir a entrada por vírgulas para obter as entradas individuais dos produtos
- Para cada entrada, dividir por dois-pontos para separar o nome, o preço e a quantidade
- Converter a string do preço para um float64 e a string da quantidade para um inteiro
- Criar uma struct
Producte armazenar um ponteiro para ela no mapa
- Manter os nomes dos produtos em uma slice separada durante a análise, na ordem em que aparecem na entrada. Percorrer um mapa em Go visita as chaves em uma ordem aleatória, portanto a slice é o que mantém cada listagem na ordem da entrada.
- Exibir o estoque inicial com o cabeçalho
"Initial Inventory:" - Exibir cada produto no formato:
"[name]: $[price] (Stock: [quantity])" - Analisar e aplicar as operações de atualização a partir da terceira entrada:
- Dividir a entrada por vírgulas para obter as operações individuais
- Para cada operação, dividir por dois-pontos para obter o tipo da operação, o nome do produto e o novo valor
- Atualizar o campo apropriado diretamente por meio do ponteiro no mapa
- Imprimir cada atualização no formato:
"Updated [product]: [field] changed to [new_value]"
- Exibir o estoque atualizado com o cabeçalho
"Updated Inventory:" - Exibir cada produto novamente no mesmo formato da exibição inicial
- Calcular e exibir o valor total do estoque:
"Total Inventory Value: $[total_value]"
Use o pacote strconv para converter as strings de preço e quantidade para seus respectivos tipos numéricos. Formate todos os preços com 2 casas decimais ao exibi-los. Este desafio demonstra como armazenar ponteiros em mapas permite modificar diretamente os dados da struct original, tornando as atualizações do estoque imediatas e persistentes, sem a necessidade de reatribuir valores ao mapa.
Experimente você mesmo
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
// Ler a entrada
var numProductsStr string
var productDataStr string
var operationsStr string
fmt.Scanln(&numProductsStr)
fmt.Scanln(&productDataStr)
fmt.Scanln(&operationsStr)
// TODO: Defina a struct Product aqui
// TODO: Crie um map para armazenar ponteiros de produtos
// TODO: Crie um slice para manter a ordem dos produtos (para garantir saída consistente)
// TODO: Faça o parse dos dados dos produtos e popule o map
// Lembre-se de:
// - Divida productDataStr por vírgulas para obter as entradas individuais
// - Para cada entrada, divida por dois-pontos para obter name, price, quantity
// - Converta as strings de price e quantity para os tipos apropriados
// - Armazene o ponteiro para a struct Product no map
// - Adicione o name do produto ao slice de ordem
// TODO: Display initial inventory
// Use o slice de ordem para iterar pelos produtos de forma consistente
// Formato: "[name]: $[price] (Stock: [quantity])"
// TODO: Analisar e aplicar as operações de atualização
// Lembre-se de:
// - Divida operationsStr por vírgulas para obter as operações individuais
// - Para cada operação, divida por dois-pontos para obter type, name, value
// - Atualize o campo apropriado diretamente através do ponteiro do map
// - Imprima a mensagem de atualização para cada operação
// TODO: Display updated inventory
// Novamente, use o slice order para uma saída consistente
// Calcule o valor total enquanto exibe
// TODO: Calculate and display total inventory value
// Format: "Total Inventory Value: $[total_value]"
}Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Lógica & Fluxo
1Fluxo de Controle Avançado
Switch com `fallthrough`Interrompendo Loops AninhadosContinuando um Loop EspecíficoA Instrução `goto`Recapitulação - Controle de Loop Avançado4Projeto: Lista de Tarefas Simples
Configuração do ProjetoAdicionando uma Tarefa2Structs e Métodos
Definindo Métodos em StructsRecebedores de ValorRecebedores de PonteiroEscolhendo RecebedoresMétodos vs FunçõesRecapitulação - Comportamento de Structs5Mapas em Profundidade
Mapas de StructsPonteiros como Valores de MapVerificando Mapas NilComparando MapasRecapitulação - Contador de Frequência de Palavras3Interfaces (O Básico)
O que é uma Interface?Definindo uma InterfaceImplementando uma InterfaceUsando Tipos de InterfaceInterface VaziaAsserções de TipoType SwitchRecapitulação - Formas e ComportamentosPratique por conta própria: Compilador de Go online