Structs
Nesta aula, você aprenderá sobre structs em Go, incluindo definição, campos, inicialização e structs anônimas. Structs são tipos de dados compostos que permitem agrupar campos de diferentes tipos, sendo fundamentais para modelar dados complexos.
Em Go, structs são tipos de dados compostos que permitem agrupar campos de diferentes tipos em uma única unidade lógica. Elas são a principal forma de criar estruturas de dados personalizadas, semelhantes a classes em outras linguagens, mas sem herança. Structs são amplamente utilizadas para modelar entidades do mundo real, como um cliente, um produto ou uma transação.
Nesta aula, abordaremos a definição de structs, seus campos, formas de inicialização e o uso de structs anônimas. Ao final, você será capaz de criar e utilizar structs de maneira eficiente em seus programas Go.
Definição
Uma struct é definida usando a palavra-chave type seguida do nome da struct e da palavra-chave struct. A definição inclui uma lista de campos entre chaves, onde cada campo possui um nome e um tipo. A sintaxe básica é:
type NomeStruct struct {
campo1 tipo1
campo2 tipo2
// ...
}Por exemplo, para representar um ponto no plano cartesiano, podemos definir:
type Ponto struct {
X float64
Y float64
}Uma vez definida, a struct pode ser usada para criar variáveis do tipo Ponto. A definição da struct em si não aloca memória; ela apenas declara um novo tipo. A alocação ocorre quando criamos valores ou variáveis desse tipo.
Campos
Os campos de uma struct são acessados usando a notação de ponto (.). Cada campo pode ser de qualquer tipo, incluindo outros structs, slices, maps, etc. Os campos podem ser exportados (públicos) se iniciarem com letra maiúscula, ou não exportados (privados) se iniciarem com letra minúscula. Isso controla a visibilidade fora do pacote.
Exemplo de acesso a campos:
var p Ponto
p.X = 10.5
p.Y = 20.3
fmt.Println(p.X, p.Y) // 10.5 20.3Structs podem conter campos de tipos complexos, como slices e maps. Por exemplo:
type Aluno struct {
Nome string
Idade int
Notas []float64
Tags map[string]string
}É importante notar que os campos de uma struct são valores, não referências. Quando você atribui uma struct a outra variável, todos os campos são copiados. Para compartilhar a mesma struct, use ponteiros.
Inicialização
Existem várias maneiras de inicializar uma struct em Go. A forma mais comum é usar um literal de struct, que pode ser feito de duas maneiras: com nomes dos campos ou sem nomes (ordem dos campos).
Literal com nomes dos campos
p := Ponto{X: 10.0, Y: 20.0}Você pode omitir campos que devem permanecer com valor zero. Por exemplo:
p := Ponto{X: 10.0} // Y será 0.0Literal sem nomes (ordem dos campos)
p := Ponto{10.0, 20.0}Nesse caso, os valores devem ser fornecidos na mesma ordem da declaração dos campos. Essa forma é menos robusta, pois se a ordem dos campos mudar, o código quebra.
Também é possível inicializar uma struct usando a função new ou com & para obter um ponteiro:
p := new(Ponto) // retorna *Ponto com todos campos zero
p.X = 5
p2 := &Ponto{X: 1, Y: 2} // ponteiro para structSe você não inicializar os campos, eles assumem o valor zero do tipo (0 para numéricos, false para booleanos, "" para strings, nil para slices/maps/ponteiros).
Structs anônimas
Structs anônimas são structs sem um nome definido explicitamente. Elas são úteis para criar estruturas temporárias, como em testes ou para agrupar dados em uma função sem precisar declarar um tipo global. A sintaxe é semelhante à definição de struct, mas sem a palavra-chave type e sem nome.
Exemplo:
func main() {
pessoa := struct {
Nome string
Idade int
}{
Nome: "Alice",
Idade: 30,
}
fmt.Println(pessoa)
}Structs anônimas são frequentemente usadas em conjunto com JSON, por exemplo, para decodificar dados sem criar um tipo nomeado. Elas também são úteis em funções que retornam múltiplos valores heterogêneos, embora isso possa ser feito com tuplas implícitas.
Uma limitação é que structs anônimas não podem ser reutilizadas em outros lugares, pois não têm nome. Para reutilização, prefira definir um tipo nomeado.
Boas práticas
- Use nomes significativos para os campos e para a struct.
- Prefira inicialização com nomes dos campos para evitar erros de ordem.
- Evite structs muito grandes; considere separar em structs menores.
- Use ponteiros para structs grandes para evitar cópias desnecessárias.
- Structs anônimas são úteis para uso local, mas não abuse.
Referências
- Go Specification: Struct Types
- A Tour of Go: Structs
- Go by Example: Structs
- DigitalOcean: Defining Structs in Go
- Medium: Structs in Go
Exercícios
Crie uma struct chamada
Livrocom camposTitulo(string),Autor(string) eAno(int). Inicialize um valor dessa struct usando um literal com nomes e imprima-o.✓ Resposta:type Livro struct { Titulo string Autor string Ano int } func main() { livro := Livro{Titulo: "1984", Autor: "George Orwell", Ano: 1949} fmt.Println(livro) }Defina uma struct
Retangulocom camposLarguraeAltura(float64). Escreva uma função que receba umRetanguloe retorne sua área. Teste com um retângulo de largura 10 e altura 5.✓ Resposta:type Retangulo struct { Largura float64 Altura float64 } func area(r Retangulo) float64 { return r.Largura * r.Altura } func main() { r := Retangulo{Largura: 10, Altura: 5} fmt.Println(area(r)) // 50 }Crie uma struct anônima para representar um carro com campos
MarcaeModelo. Inicialize-a com valores e imprima.✓ Resposta:func main() { carro := struct { Marca string Modelo string }{ Marca: "Fiat", Modelo: "Uno", } fmt.Println(carro) }Dada a struct
Pessoacom camposNomeeIdade, escreva um código que crie um ponteiro para uma struct Pessoa, modifique a idade e imprima o valor original e o modificado.✓ Resposta:type Pessoa struct { Nome string Idade int } func main() { p := &Pessoa{Nome: "João", Idade: 25} fmt.Println("Antes:", *p) p.Idade = 30 fmt.Println("Depois:", *p) }Crie uma struct
Timecom camposNome(string) eJogadores(slice de strings). Inicialize com um time de futebol com 3 jogadores e depois adicione um quarto jogador usando append. Imprima o time final.✓ Resposta:type Time struct { Nome string Jogadores []string } func main() { t := Time{ Nome: "Flamengo", Jogadores: []string{"Gabigol", "Arrascaeta", "Bruno Henrique"}, } t.Jogadores = append(t.Jogadores, "Everton Ribeiro") fmt.Println(t) }