Go: Go Map e Estruturas

Última atualização: 2026-08-26

Os maps e as structs são os dois pilares da modelagem de dados em Go — os maps lidam com consultas dinâmicas, enquanto as structs descrevem estruturas fixas — e, juntos, podem descrever 90% dos objetos de negócios.

Os mapas permitem consultas de chave-valor em O(1), enquanto as estruturas agregam dados por meio de campos. Nesta lição, você vai dominar todos os conceitos fundamentais da modelagem de dados em Go e será capaz de usá-los para construir um sistema completo de estoque para comércio eletrônico.

1. Você aprenderá


2. A história real de um engenheiro de comércio eletrônico

(1) Problema: as consultas de fatias são muito lentas

Bob é engenheiro de back-end em uma plataforma de comércio eletrônico. Com a campanha de pré-venda do Double 11 em andamento, a API de consulta de estoque tem estado incrivelmente lenta:

“Temos 100.000 SKUs em estoque, armazenadas usando uma fatia []Product, e cada consulta envolve uma varredura linear. À medida que o QPS aumenta, o tempo médio de resposta é de 800 ms, com 100% de uso da CPU. Meu chefe me deu três dias para otimizar isso para menos de 100 ms.”

Ele abriu o código que havia escrito:

GO
// Version 1: Store all products using a slice
var products []Product

func findProduct(sku string) *Product {
    for _, p := range products {  // O(n) linear scan
        if p.SKU == sku {
            return &p
        }
    }
    return nil
}

100.000 produtos × 1.000 QPS = 100 milhões de varreduras por segundo; a utilização de 100% da CPU é inevitável.

(2) Solução em Go: use um mapa para consultas em O(1)

GO
// inventory.go
package main

import "fmt"

type Product struct {
    SKU      string  // Product unique identifier
    Name     string  // Product name
    Price    float64 // Price
    Stock    int     // Stock count
    Category string  // Classification
}

// Using map to create a hash table
type Inventory struct {
    products map[string]Product  // SKU -> Product
}

func NewInventory() *Inventory {
    return &Inventory{products: make(map[string]Product)}
}

// O(1) query
func (inv *Inventory) Find(sku string) (Product, bool) {
    p, ok := inv.products[sku]
    return p, ok
}

// O(1) update
func (inv *Inventory) UpdateStock(sku string, delta int) error {
    p, ok := inv.products[sku]
    if !ok {
        return fmt.Errorf("SKU %s not found", sku)
    }
    p.Stock += delta
    inv.products[sku] = p
    return nil
}

func main() {
    inv := NewInventory()

    // Bulk import of 100,000 SKUs
    for i := 0; i < 100000; i++ {
        sku := fmt.Sprintf("SKU-%05d", i)
        inv.products[sku] = Product{
            SKU:      sku,
            Name:     fmt.Sprintf("Product-%d", i),
            Price:    99.99,
            Stock:    100,
            Category: "electronics",
        }
    }

    // Query performance comparison
    p, ok := inv.Find("SKU-50000")
    if ok {
        fmt.Printf("Found: %s, price=%.2f\n", p.Name, p.Price)
    }

    // Update inventory
    inv.UpdateStock("SKU-50000", -5)
}

Resultado:

TEXT 📖 Somente leitura
Found: Product-50000, price=99.99

(3) Desempenho: Desempenho das consultas com slice versus map

Tamanho dos dados Varredura linear no corte Consulta por hash no mapa Diferença de desempenho
100 SKUs 50 ns 50 ns equivalente
1.000 SKUs 500 ns 50 ns 10x
10.000 SKUs 5 µs 50 ns 100x
100.000 SKUs 50 µs 50 ns 1.000x
💡 Dica: A complexidade O(1) de um mapa é a complexidade média baseada em uma tabela hash — no pior caso (colisões de hash), ela se degrada para O(n). O Go minimiza essa probabilidade por meio de uma função hash bem projetada e de um mecanismo de redimensionamento.


3. Noções básicas sobre mapas

(1) Três maneiras de criar um mapa

GO
package main

import "fmt"

func main() {
    // Method 1: make (Recommended)
    m1 := make(map[string]int)  // empty map, writable

    // Method 2: make + pre-allocated capacity
    m2 := make(map[string]int, 100)  // pre-allocate 100 capacity, reduce resizing

    // Method 3: Literal Initialization
    m3 := map[string]int{
        "Alice": 28,
        "Bob":   32,
    }

    // Method 4: nil map (read-only, cannot be written to)
    var m4 map[string]int  // == nil, cannot do m4["a"] = 1
    _ = m4
}

(2) CRUD de mapa

GO
package main

import "fmt"

func main() {
    ages := make(map[string]int)

    // Create
    ages["Alice"] = 28
    ages["Bob"] = 32

    // Read
    fmt.Println(ages["Alice"])  // 28

    // Update
    ages["Alice"] = 29

    // Delete
    Excluir(ages, "Bob")

    // Length
    fmt.Printf("len=%d\n", len(ages))

    fmt.Println(ages)  // map[Alice:29]
}

Saída:

TEXT 📖 Somente leitura
28
len=1
map[Alice:29]

(3) ▶ Exemplo: iteração no mapa (a ordem é aleatória)

GO
package main

import "fmt"

func main() {
    ages := map[string]int{"Alice": 28, "Bob": 32, "Charlie": 45}

    // for range: key + value
    for name, age := range ages {
        fmt.Printf("%s is %d years old\n", name, age)
    }

    // Only the key
    for name := range ages {
        fmt.Printf("name: %s\n", name)
    }

    // Only the value (use _ to ignore the key)
    for _, age := range ages {
        fmt.Printf("age: %d\n", age)
    }
}
▶ Experimente

Saída (em ordem aleatória):

TEXT 📖 Somente leitura
Alice is 28 years old
Charlie is 45 years old
Bob is 32 years old
name: Bob
...
🔥 Erro comum: A ordem de iteração de um mapa em Go é intencionalmente aleatória — para evitar que os programadores dependam de uma ordem específica. Se você precisar de uma ordem consistente, classifique as chaves primeiro.


4. Sintaxe “comma-ok” (Ponto-chave)

(1) Distinguir entre “valor zero” e “não existe”

GO
package main

import "fmt"

func main() {
    ages := map[string]int{"Alice": 28}

    // Incorrect approach: Cannot distinguish between "key does not exist" and "value = 0"
    age := ages["Bob"]
    fmt.Printf("Bob's age: %d\n", age)  // 0 (but is Bob really 0 years old?)

    // Correct approach: comma-ok
    age, ok := ages["Bob"]
    if ok {
        fmt.Printf("Bob's age: %d\n", age)
    } else {
        fmt.Println("Bob not found")
    }

    // Just check if it exists: discard the value
    _, exists := ages["Bob"]
    fmt.Printf("Bob exists: %v\n", exists)
}

Saída:

TEXT 📖 Somente leitura
Bob's age: 0
Bob not found
Bob exists: false

(2) O uso da vírgula na prática: armazenamento em cache de consultas

GO
package main

import "fmt"

// Cache: key → value
var cache = make(map[string]string)

func getCached(key string) (string, bool) {
    val, ok := cache[key]
    return val, ok
}

func main() {
    // Set cache
    cache["user:1"] = "Alice"
    cache["user:2"] = "Bob"

    // Query cache
    if val, ok := getCached("user:1"); ok {
        fmt.Printf("Hit: %s\n", val)
    } else {
        fmt.Println("Miss")
    }

    if _, ok := getCached("user:999"); !ok {
        fmt.Println("user:999 not in cache, fetching from DB...")
    }
}

Saída:

TEXT 📖 Somente leitura
Hit: Alice
user:999 not in cache, fetching from DB...

(3) Padrão geral “comma-ok”

Contexto Sintaxe Significado
Pesquisa no mapa v, ok := m[key] A chave existe?
Asserção de tipo v, ok := x.(T) Correspondência de tipo?
Recebendo do canal v, ok := <-ch Canal fechado?

5. Noções básicas sobre estruturas

(1) Definição e inicialização de estruturas

GO
package main

import "fmt"

// define struct
type User struct {
    Name string
    Age  int
    City string
}

func main() {
    // Method 1: By field Ordem (not recommended; poor readability)
    u1 := User{"Alice", 28, "Shanghai"}

    // Method 2: Initializing Field Names (Recommended)
    u2 := User{
        Name: "Bob",
        Age:  32,
        City: "Beijing",
    }

    // Method 3: Partial Initialization (with the remainder set to zero)
    u3 := User{Name: "Charlie"}  // Age=0, City=""

    // Method 4: new() returns a pointer
    u4 := new(User)
    u4.Name = "Dave"

    fmt.Println(u1, u2, u3, u4)
}

Saída:

TEXT 📖 Somente leitura
{Alice 28 Shanghai} {Bob 32 Beijing} {Charlie  } &{Dave 0 }

(2) Acesso e modificação de campos

GO
package main

import "fmt"

type User struct {
    Name string
    Age  int
}

func main() {
    u := User{Name: "Alice", Age: 28}

    // Read field
    fmt.Println(u.Name)  // Alice

    // Write to a field
    u.Age = 29

    // Pointer access (automatic dereferencing)
    p := &u
    fmt.Println(p.Name)  // Alice (equivalent to (*p).Name)
    p.Age = 30  // automatic dereferencing
}

(3) ▶ Exemplo: Cópia de estruturas versus ponteiros

GO
package main

import "fmt"

type Counter struct {
    Value int
}

// Pass-by-value: Copy the entire struct
func incrementByValue(c Counter) {
    c.Value++  // modifies the copy
    fmt.Printf("Inside Função: %d\n", c.Value)
}

// Pointer passing: pass by reference
func incrementByPointer(c *Counter) {
    c.Value++  // modifies the original
    fmt.Printf("Inside Função: %d\n", c.Value)
}

func main() {
    c := Counter{Value: 10}

    incrementByValue(c)
    fmt.Printf("After value passing: %d\n", c.Value)  // 10 (unchanged)

    incrementByPointer(&c)
    fmt.Printf("After pointer passing: %d\n", c.Value)  // 11 (modified)
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
Inside function: 11
After value passing: 10
Inside function: 11
After pointer passing: 11
🔥 Erro comum: Uma struct é um tipo de valor; portanto, ao passá-la como parâmetro, toda a struct é copiada. No caso de structs grandes ou quando for necessário modificar o objeto original, você deve usar um ponteiro.


6. struct tag (Chave para a serialização em JSON)

(1) Sintaxe da estrutura tag

GO
type User struct {
    Name     string `json:"name" db:"user_name"`
    Age      int    `json:"age" validate:"min=0,max=150"`
    Email    string `json:"email,omitempty"`
    Password string `json:"-"`  // - means JSON ignores this field
}

(2) Prática de serialização em JSON

GO
package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    Name     string `json:"name"`
    Age      int    `json:"age"`
    Email    string `json:"email,omitempty"`
    Password string `json:"-"`  // password not serialized
}

func main() {
    u := User{
        Name:     "Alice",
        Age:      28,
        Email:    "alice@example.com",
        Password: "secret123",
    }

    // Serialization: struct → JSON
    data, _ := json.Marshal(u)
    fmt.Printf("JSON: %s\n", data)

    // Deserialization: JSON → struct
    jsonStr := `{"name":"Bob","age":32,"email":"bob@example.com"}`
    var u2 User
    json.Unmarshal([]byte(jsonStr), &u2)
    fmt.Printf("Deserialization: %+v\n", u2)
}

Saída:

TEXT 📖 Somente leitura
JSON: {"name":"Alice","age":28,"email":"alice@example.com"}
Deserialization: {Name:Bob Age:32 Email:bob@example.com Password:}

(3) Bibliotecas de tags de estruturas comumente utilizadas

Biblioteca Nome da tag Finalidade
encoding/json json:"name" Campo JSON name
gorm gorm:"primaryKey" Restrições de campos ORM
validador validate:"required" Validação de campo
yaml yaml:"name" Serialização YAML
💡 Dica: A lição 10, “file-json”, abordará em profundidade todos os detalhes da serialização JSON.


7. Estruturas aninhadas

(1) Estruturas aninhadas (composição em vez de herança)

O Go não possui herança; ele utiliza estruturas aninhadas para alcançar a composição:

GO
package main

import "fmt"

type Address struct {
    City    string
    Country string
}

type User struct {
    Name    string
    Age     int
    Address Address  // nested Address
}

func main() {
    u := User{
        Name: "Alice",
        Age:  28,
        Address: Address{
            City:    "Shanghai",
            Country: "China",
        },
    }

    // Accessing nested fields
    fmt.Println(u.Address.City)     // Shanghai
    fmt.Println(u.Address.Country)  // China
}

(2) Aninhamento anônimo (promoção de campo)

GO
package main

import "fmt"

type Address struct {
    City    string
    Country string
}

// Anonymous nesting: fields are "promoted"
type User struct {
    Name string
    Age  int
    Address  // equivalent to Address Address, but without the field name
}

func main() {
    u := User{
        Name: "Alice",
        Age:  28,
        Address: Address{
            City:    "Shanghai",
            Country: "China",
        },
    }

    // Field promotion: direct access, without u.Address.City
    fmt.Println(u.City)     // Shanghai
    fmt.Println(u.Country)  // China

    // You can also use the full path
    fmt.Println(u.Address.City)
}

(3) ▶ Exemplo: Tags aninhadas + JSON na prática

GO
package main

import (
    "encoding/json"
    "fmt"
)

type Address struct {
    City    string `json:"city"`
    Country string `json:"country"`
}

type User struct {
    Name    string  `json:"name"`
    Age     int     `json:"age"`
    Email   string  `json:"email,omitempty"`
    Address Address `json:"address"`
}

func main() {
    u := User{
        Name:  "Alice",
        Age:   28,
        Email: "alice@example.com",
        Address: Address{
            City:    "Shanghai",
            Country: "China",
        },
    }

    data, _ := json.MarshalIndent(u, "", "  ")
    fmt.Println(string(data))
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
{
  "name": "Alice",
  "age": 28,
  "email": "alice@example.com",
  "address": {
    "city": "Shanghai",
    "country": "China"
  }
}

8. Escolhendo entre map e slice

(1) Tabela de referência para seleção de modelos

Dimensão fatia []T mapa map[K]V
Método de consulta Varredura linear O(n) Hash O(1)
Está ordenado? ✅ Ordenado ❌ Não ordenado
Uso de memória Compacto (24 + len*size) Menos compacto (tabela hash + bucket)
Excluir um elemento Requer movimentação manual delete(m, k) O(1)
Cenários típicos Listas/Filas/Pilhas/Classificação Dicionários/Caches/Índices

(2) Árvore de decisão para seleção de modelos

100%
graph TB
    A[Need to store multiple elements] --> B{Need to look up by key?}
    B -->|Yes| C[Use map<br/>O(1) lookup]
    B -->|No| D{Need to maintain order?}
    D -->|Yes| E[Use slice]
    D -->|No| F{Element count < 100?}
    F -->|Yes| G[Either slice or map works]
    F -->|No| C

(3) Exemplo prático: gestão de notas dos alunos

GO
package main

import "fmt"

// Store student grades in a map (look up by student ID)
type GradeBook struct {
    scores map[string]int  // Student ID → Score
}

func (gb *GradeBook) Set(id string, score int) {
    gb.scores[id] = score
}

func (gb *GradeBook) Get(id string) (int, bool) {
    score, ok := gb.scores[id]
    return score, ok
}

// Use a slice to store a list of scores (for sorting or calculating the average)
func average(scores []int) float64 {
    if len(scores) == 0 {
        return 0
    }
    sum := 0
    for _, s := range scores {
        sum += s
    }
    return float64(sum) / float64(len(scores))
}

func main() {
    gb := &GradeBook{scores: make(map[string]int)}
    gb.Set("S001", 95)
    gb.Set("S002", 82)
    gb.Set("S003", 67)

    if s, ok := gb.Get("S001"); ok {
        fmt.Printf("S001: %d\n", s)
    }

    // Collect all scores and calculate the average
    allScores := []int{}
    for _, s := range gb.scores {
        allScores = append(allScores, s)
    }
    fmt.Printf("Average Score: %.2f\n", average(allScores))
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
S001: 95
Average Score: 81.33
💡 Dica: Em projetos reais, é comum usar map e slice em conjunto — map para consultas e slice para ordenação ou agregação.


9. Exemplo completo: Sistema de estoque de SKUs para comércio eletrônico

Combine todos os recursos de mapas e estruturas para criar um sistema completo de consulta de estoque para comércio eletrônico:

GO
// inventory_system.go
package main

import (
    "encoding/json"
    "fmt"
    "sort"
)

// Product
type Product struct {
    SKU      string   `json:"sku"`
    Name     string   `json:"name"`
    Price    float64  `json:"price"`
    Stock    int      `json:"stock"`
    Category string   `json:"category"`
    Tags     []string `json:"tags,omitempty"`  // Tags: new/hot/discount
}

// Inventory System
type Inventory struct {
    products map[string]Product  // SKU → Product
}

func NewInventory() *Inventory {
    return &Inventory{products: make(map[string]Product)}
}

// Add product
func (inv *Inventory) Add(p Product) {
    inv.products[p.SKU] = p
}

// Query (comma-ok)
func (inv *Inventory) Find(sku string) (Product, bool) {
    p, ok := inv.products[sku]
    return p, ok
}

// Update stock
func (inv *Inventory) UpdateStock(sku string, delta int) error {
    p, ok := inv.products[sku]
    if !ok {
        return fmt.Errorf("SKU %s not found", sku)
    }
    newStock := p.Stock + delta
    if newStock < 0 {
        return fmt.Errorf("insufficient stock for %s: have %d, need %d",
            sku, p.Stock, -delta)
    }
    p.Stock = newStock
    inv.products[sku] = p
    return nil
}

// Sort by price (unordered map → convert to slice)
func (inv *Inventory) ListByPrice() []Product {
    list := make([]Product, 0, len(inv.products))
    for _, p := range inv.products {
        list = append(list, p)
    }
    sort.Slice(list, func(i, j int) bool {
        return list[i].Price < list[j].Price
    })
    return list
}

// Filter by category
func (inv *Inventory) FindByCategory(category string) []Product {
    var result []Product
    for _, p := range inv.products {
        if p.Category == category {
            result = append(result, p)
        }
    }
    return result
}

func main() {
    inv := NewInventory()

    // Initialize 100 SKUs
    categories := []string{"electronics", "clothing", "food"}
    for i := 0; i < 100; i++ {
        inv.Add(Product{
            SKU:      fmt.Sprintf("SKU-%05d", i),
            Name:     fmt.Sprintf("Product-%d", i),
            Price:    float64(i%50 + 10),
            Stock:    100 - i%30,
            Category: categories[i%3],
        })
    }

    // 1. Look up a single SKU
    if p, ok := inv.Find("SKU-0050"); ok {
        fmt.Printf("Found: %s, price=%.2f, stock=%d\n", p.Name, p.Price, p.Stock)
    }

    // 2. Update inventory
    if err := inv.UpdateStock("SKU-0050", -10); err == nil {
        fmt.Println("Stock updated successfully")
    }

    // 3. Filter by category
    electronics := inv.FindByCategory("electronics")
    fmt.Printf("\nElectronics products: %d\n", len(electronics))

    // 4. Sort by price (top 3)
    sorted := inv.ListByPrice()
    fmt.Println("\nTop 3 cheapest:")
    for i, p := range sorted[:3] {
        fmt.Printf("  %d. %s: %.2f\n", i+1, p.Name, p.Price)
    }

    // 5. JSON Serialization (API Response)
    if p, ok := inv.Find("SKU-0050"); ok {
        data, _ := json.MarshalIndent(p, "", "  ")
        fmt.Printf("\nJSON output:\n%s\n", data)
    }
}

Resultado esperado:

TEXT 📖 Somente leitura
Found: Product-50, price=10.00, stock=70
Stock updated successfully

Electronics products: 34

Top 3 cheapest:
  1. Product-0: 10.00
  2. Product-30: 10.00
  3. Product-60: 10.00

JSON output:
{
  "sku": "SKU-0050",
  "name": "Product-50",
  "price": 10,
  "stock": 60,
  "category": "food"
}
🔥 Erro comum: No método ListByPrice, sort.Slice usa um closure como função de comparação. O closure captura a variável list e a chama durante cada comparação.


10. Conjuntos de exemplos adicionais

(1) ▶ Exemplo: Comparação de desempenho entre a inicialização com um literal de mapa e o uso de make

GO
package main

import (
    "fmt"
    "time"
)

func main() {
    // Literal initialization
    start1 := time.Now()
    m1 := map[string]int{
        "a": 1, "b": 2, "c": 3, "d": 4, "e": 5,
        "f": 6, "g": 7, "h": 8, "i": 9, "j": 10,
    }
    fmt.Printf("Literals: %v, %v\n", len(m1), time.Since(start1))

    // make pre-allocation
    start2 := time.Now()
    m2 := make(map[string]int, 10)
    m2["a"] = 1
    m2["b"] = 2
    m2["c"] = 3
    m2["d"] = 4
    m2["e"] = 5
    m2["f"] = 6
    m2["g"] = 7
    m2["h"] = 8
    m2["i"] = 9
    m2["j"] = 10
    fmt.Printf("make: %v, %v\n", len(m2), time.Since(start2))
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
Literals: 10, 1.2µs
make: 10, 850ns

(2) ▶ Exemplo: Métodos que aceitam valores de estrutura versus métodos que aceitam ponteiros

GO
package main

import "fmt"

type Counter struct {
    Value int
}

// Value receiver: operates on a copy; does not affect the original
func (c Counter) IncrementValue() Counter {
    c.Value++
    return c
}

// Pointer receiver: directly modifies the original
func (c *Counter) IncrementPointer() {
    c.Value++
}

func main() {
    c := Counter{Value: 10}

    // Value receiver: must use the return value
    c = c.IncrementValue()
    fmt.Printf("After value receiver: %d\n", c.Value)  // 11

    // Pointer receiver: direct modification
    c.IncrementPointer()
    fmt.Printf("After pointer receiver: %d\n", c.Value)  // 12
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
After value receiver: 11
After pointer receiver: 12

(3) ▶ Exemplo: Demonstração das armadilhas da concorrência na função map

GO
package main

import (
    "fmt"
    "time"
)

func main() {
    m := make(map[string]int)

    // Writing goroutine
    go func() {
        for i := 0; i < 1000; i++ {
            m["key"] = i  // write operation
        }
    }()

    // Reading goroutine
    go func() {
        for i := 0; i < 1000; i++ {
            _ = m["key"]  // read operation
        }
    }()

    time.Sleep(100 * time.Millisecond)
    fmt.Println("Concurrent reads and writes may cause a panic (fatal error: concurrent map read and map write)")
}
▶ Experimente

Saída (pode causar um erro grave durante a execução):

TEXT 📖 Somente leitura
Concurrent reads and writes may cause a panic (fatal error: concurrent map read and map write)
🔥 Erro comum: Essa é uma armadilha clássica na concorrência em Go. Os mapas concorrentes devem ser protegidos com sync.Map ou sync.Mutex; isso é abordado em detalhes na Lição 16.


❓ Perguntas Frequentes

P: O que acontece se você tentar acessar uma chave inexistente em um mapa? R: É retornado o valor zero. No entanto, um valor zero pode ser válido (por exemplo, idade=0); portanto, você deve usar “comma-ok” para distinguir entre “não existe” e “o valor é zero”.

P: O map é um tipo de referência? R: Sim. Uma variável map é um ponteiro para uma tabela hash; tanto a atribuição quanto a passagem de parâmetros compartilham a mesma tabela hash subjacente. É semelhante a uma fatia, mas mais radical — enquanto uma fatia pode acionar o redimensionamento de forma isolada por meio do append, um map não possui esse mecanismo de isolamento.

P: É possível comparar estruturas? R: Somente se todos os campos forem comparáveis. Estruturas que contenham fatias, mapas ou funções não podem ser comparadas (erro de compilação). Use reflect.DeepEqual() para uma comparação profunda.

P: Quando se deve usar estruturas aninhadas e quando se deve usar ponteiros? R: (1) Se for necessário modificar o objeto original → use ponteiros aninhados; (2) Se a estrutura for grande → use ponteiros aninhados (para evitar cópias); (3) Se for necessário polimorfismo (para implementar uma interface) → use ponteiros; (4) Semântica de valor, objetos imutáveis → use aninhamento de valores.

P: Quais são as restrições para as chaves de mapas? R: As chaves devem ser de tipos comparáveis — bool, int, float ou string — ou estruturas que contenham esses tipos. Elas não podem ser slices, mapas ou func.

P: O que acontece se o formato da tag da estrutura estiver incorreto? R: O código será compilado, mas bibliotecas como a de serialização JSON não conseguirão reconhecê-lo. Erros comuns incluem: erros ortográficos no nome da tag (por exemplo, um espaço a mais em json:"name") ou o uso do tipo errado de aspas (é preciso usar aspas duplas).

P: Por que a iteração sobre um mapa é aleatória? R: Isso faz parte do design do Go — para evitar que os programadores dependam de uma ordem específica. Se você precisar de uma ordem consistente, primeiro use uma fatia para coletar todas as chaves, depois classifique as chaves e, por fim, consulte o mapa usando as chaves classificadas.

P: Um mapa é seguro para múltiplos threads? R: Não! Se várias goroutines lerem e gravarem no mesmo mapa simultaneamente, ocorrerá um panic (“leitura e gravação simultâneas no mapa”). Em cenários simultâneos, use sync.Map (Lição 16) ou adicione um mutex (Lição 16).


📖 Resumo


📝 Exercícios

  1. Problema básico (Dificuldade ⭐): Use map[string]int para contar o número de vezes que cada palavra aparece em um texto. Dada a entrada "the quick brown fox jumps over the lazy dog the", a saída deve ser map[the:3 quick:1 brown:1 ...].

  2. Problema Avançado (Dificuldade ⭐⭐): Defina uma estrutura Student (Name string, Scores []int) e implemente os seguintes métodos: (1) Average() float64 para calcular a nota média; (2) Grade() string para retornar uma nota (A/B/C/D/F); (3) Teste com pelo menos 3 alunos.

  3. Problema de desafio (Dificuldade ⭐⭐⭐): Implemente um aplicativo de lista de contatos: armazene contatos usando map[string]Contact (onde Contact inclui Nome, Telefone, E-mail e Grupo); implemente (1) adicionar, excluir e pesquisar; (2) filtragem por grupo (família/amigos/trabalho); (3) exportação para um arquivo JSON (usando os.WriteFile). Requisitos: tratamento completo de erros + tags JSON + pelo menos 10 contatos de teste.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%