Structs
Esta aula aborda structs em Go, desde sua definição e campos até inicialização e structs anônimas. Inclui exemplos práticos e exercícios para fixação.
Structs são tipos de dados compostos em Go que agrupam campos de diferentes tipos sob um mesmo nome. Elas são fundamentais para modelar entidades do mundo real, como pessoas, produtos ou registros de banco de dados. Diferente de arrays ou slices que armazenam elementos homogêneos, structs permitem heterogeneidade.
Nesta aula, aprenderemos a declarar structs, definir seus campos, inicializá-las de várias formas e usar structs anônimas para situações pontuais.
Definição
Uma struct é definida com a palavra-chave type seguida do nome e da palavra struct. A declaração fica geralmente no nível do pacote, mas pode ser local. Exemplo:
type Pessoa struct {
Nome string
Idade int
}Após a definição, podemos usar Pessoa como um tipo qualquer. A struct criada é um tipo nomeado, o que facilita a reutilização e documentação.
Campos
Campos são as variáveis que compõem a struct. Cada campo tem um nome e um tipo. Eles podem ser de qualquer tipo, inclusive outras structs, slices, maps, etc. Acessamos os campos usando a notação ponto (.).
var p Pessoa
p.Nome = "João"
p.Idade = 30
fmt.Println(p.Nome) // JoãoCampos podem ter tags (metadados) usadas por bibliotecas como JSON, mas isso é assunto avançado. Por ora, foque no básico.
Inicialização
Existem várias formas de inicializar uma struct:
- Literal com campos na ordem:
p := Pessoa{"Maria", 25}(requer todos os campos na ordem declarada). - Literal com campos nomeados:
p := Pessoa{Nome: "Carlos", Idade: 40}(mais seguro e legível). - Usando
new:p := new(Pessoa)retorna um ponteiro para uma struct com zero values. - Declaração com
var:var p Pessoainicializa com zero values.
Exemplo completo:
package main
import "fmt"
type Endereco struct {
Rua string
Numero int
}
type Pessoa struct {
Nome string
Idade int
Endereco Endereco
}
func main() {
p1 := Pessoa{
Nome: "Ana",
Idade: 28,
Endereco: Endereco{
Rua: "Av. Brasil",
Numero: 100,
},
}
fmt.Println(p1.Nome, p1.Endereco.Rua)
var p2 Pessoa
p2.Nome = "Pedro"
p2.Idade = 35
fmt.Println(p2)
}Structs anônimas
Structs anônimas são declaradas sem um nome, geralmente usadas para uso único, como em testes ou configurações rápidas. A sintaxe é struct { campos }.
p := struct {
Nome string
Idade int
}{
Nome: "João",
Idade: 30,
}
fmt.Println(p)Também podem ser usadas dentro de outras structs ou como tipo de campo. Por exemplo:
type Produto struct {
Nome string
Preco float64
Info struct {
Descricao string
Categoria string
}
}Structs anônimas são úteis para evitar a criação de tipos nomeados desnecessários, mas uso excessivo pode prejudicar a legibilidade.
Boas práticas
- Use inicialização com campos nomeados sempre que possível, para evitar erros de ordem.
- Evite structs muito grandes; considere dividir em structs menores.
- Documente campos públicos com comentários.
- Structs anônimas são boas para escopos pequenos, mas prefira tipos nomeados se houver reuso.
Exercícios
Crie uma struct
Carrocom camposMarca(string),Modelo(string) eAno(int). Inicialize-a com valores literais e imprima cada campo.✓ Resposta:package main import "fmt" type Carro struct { Marca string Modelo string Ano int } func main() { c := Carro{"Ford", "Fiesta", 2020} fmt.Println("Marca:", c.Marca) fmt.Println("Modelo:", c.Modelo) fmt.Println("Ano:", c.Ano) }Defina uma struct
Livrocom camposTitulo,AutorePaginas. Crie uma variável do tipoLivrousandovare atribua valores aos campos depois. Imprima a struct.✓ Resposta:package main import "fmt" type Livro struct { Titulo string Autor string Paginas int } func main() { var l Livro l.Titulo = "1984" l.Autor = "George Orwell" l.Paginas = 328 fmt.Println(l) }Crie uma struct anônima para representar um ponto 2D (coordenadas X e Y) e inicialize-a com valores. Imprima as coordenadas.
✓ Resposta:package main import "fmt" func main() { ponto := struct { X int Y int }{ X: 10, Y: 20, } fmt.Printf("Ponto: (%d, %d)\n", ponto.X, ponto.Y) }Defina uma struct
Funcionariocom camposNome,SalarioeEndereco(outra struct comRuaeNumero). Inicialize usando campos nomeados e acesse o endereço completo.✓ Resposta:package main import "fmt" type Endereco struct { Rua string Numero int } type Funcionario struct { Nome string Salario float64 Endereco Endereco } func main() { f := Funcionario{ Nome: "Maria", Salario: 5000.00, Endereco: Endereco{ Rua: "Rua das Flores", Numero: 123, }, } fmt.Printf("%s mora na %s, %d\n", f.Nome, f.Endereco.Rua, f.Endereco.Numero) }Crie um slice de structs
Aluno(com camposNomeeNota) e adicione três alunos. Percorra o slice e imprima o nome de cada aluno com nota maior que 7.✓ Resposta:package main import "fmt" type Aluno struct { Nome string Nota float64 } func main() { alunos := []Aluno{ {"João", 8.5}, {"Maria", 6.0}, {"Pedro", 9.2}, } for _, a := range alunos { if a.Nota > 7.0 { fmt.Println(a.Nome) } } }