Em Go, as estruturas (structs) são mecanismos fundamentais para a criação de tipos de dados personalizados, sendo amplamente utilizadas no desenvolvimento de aplicações.
Neste guia, exploraremos todos os aspectos essenciais das structs e demonstraremos como empregá-las em seus projetos Go, através de exemplos práticos.
Vamos começar esta jornada!
Introdução
Uma estrutura é, em essência, um conjunto de variáveis (denominadas campos), cada qual com seu tipo de dado específico, agrupadas em uma única unidade. Elas oferecem um método eficaz para organizar dados relacionados, formando registros customizados. Uma struct pode incluir tanto tipos primitivos quanto outros tipos definidos pelo usuário, sendo ela própria um tipo definido pelo usuário.
As structs em Go são entidades mutáveis, o que significa que seus valores podem ser alterados durante a execução do programa.
A utilização de structs contribui para a melhoria da arquitetura geral do código, permitindo a criação e manipulação de estruturas de dados complexas em diferentes partes do sistema. Por exemplo, ao invés de passar um grande número de parâmetros individualmente para uma função, o que torna o código mais confuso, pode-se passar uma única struct, que contém todos os dados necessários. Isso simplifica o código e facilita sua manutenção.
A declaração de uma struct utiliza duas palavras-chave: type e struct. Os campos são declarados entre chaves (de forma similar às classes em Java), cada campo com seu nome (identificador) e seu respectivo tipo de dado. Detalharemos a implementação na próxima seção.
Para quem possui familiaridade com Programação Orientada a Objetos (POO), é possível pensar nas structs como classes, porém sem o conceito de herança.
Definindo Estruturas
Agora que você já tem uma compreensão do conceito de structs e suas aplicações, vamos aprender a como declarar uma struct. A sintaxe básica de uma struct é:
type NomeDaStruct struct {
campo1 TipoDoCampo1
campo2 TipoDoCampo2
}
Nesta declaração, as palavras-chave type e struct são reservadas, e a estrutura contém diversos campos, cada um com seu tipo de dado específico.
Vejamos um exemplo prático:
package main
import (
"fmt"
)
type Usuario struct {
nome string
idade int
saldoBancario float32
}
func main() {
var usuario Usuario
fmt.Println(usuario)
}
Neste exemplo, criamos uma struct chamada Usuario, composta pelos campos nome (string), idade (int) e saldoBancario (float32). Na função main(), declaramos uma variável do tipo Usuario e a imprimimos. O resultado é o valor inicial/vazio da struct, uma vez que ainda não foi atribuído nenhum valor aos campos. O valor zero corresponde ao valor padrão de cada campo (zero para inteiros, strings vazias, etc).
{ 0 0}
Atribuindo Valores a Estruturas
Na seção anterior, aprendemos a declarar structs. Agora, vamos ver como inicializar ou atribuir valores aos seus campos. Observe o código abaixo:
package main
import (
"fmt"
)
type Usuario struct {
nome string
idade int
saldoBancario float32
}
func main() {
// Com nomes de campos
usuario1 := Usuario{
nome: "Pedro",
idade: 24,
saldoBancario: 100.0,
}
// Sem nomes de campos
usuario2 := Usuario{"Maria", 21, 1000.0}
fmt.Println(usuario1)
fmt.Println(usuario2)
}
O código demonstra como inicializar structs, tanto com a nomeação dos campos quanto sem ela. O resultado da execução será:
{Pedro 24 100}
{Maria 21 1000}
Caso algum campo não seja inicializado, ele receberá o valor padrão (valor zero) do seu tipo.
usuario1 := Usuario{
nome: "Pedro",
idade: 24,
}
// Saída: {Pedro 24 0.0}
Existe ainda outra forma de criar structs, utilizando a palavra-chave new. Veremos como usá-la na próxima seção.
Acessando os Campos de uma Struct
Agora que aprendemos a criar e inicializar structs, vamos explorar como acessar seus campos. Em Go, utilizamos o operador ponto para isso. Com base no exemplo anterior, vamos acessar e imprimir os campos nome e idade:
package main
import (
"fmt"
)
type Usuario struct {
nome string
idade int
saldoBancario float32
}
func main() {
// Com nomes de campos
usuario := Usuario{
nome: "Pedro",
idade: 24,
saldoBancario: 100.0,
}
fmt.Println(usuario.nome)
fmt.Println(usuario.idade)
fmt.Println(usuario.saldoBancario)
}
Aqui, utilizamos a sintaxe usuario.nome_do_campo para acessar os campos da estrutura. A saída do código acima será:
Pedro 24 100
Como mencionado anteriormente, structs podem ser criadas também com a palavra-chave new. Veja como:
usuario := new(Usuario)
usuario.nome = "Pedro"
usuario.idade = 24
usuario.saldoBancario = 100.0
fmt.Println(usuario)
// Saída: &{Pedro 24 100}
A palavra-chave new retorna um ponteiro para a estrutura recém-criada. Em Go, não é necessário desreferenciar explicitamente o ponteiro (mas fmt.Println(*usuario) resultaria na mesma saída).
Estruturas Aninhadas
Em Go, estruturas podem conter outros tipos definidos pelo usuário, ou seja, uma estrutura pode conter outras estruturas aninhadas.
package main
import (
"fmt"
)
type Usuario struct {
nome string
idade int
saldoBancario float32
detalhesCargo DetalhesCargo
}
type DetalhesCargo struct {
posicao string
equipe string
}
func main() {
detalhesCargoDePedro := DetalhesCargo{
posicao: "Engenheiro de Software",
equipe: "Transporte",
}
usuario := Usuario{
nome: "Pedro",
idade: 24,
saldoBancario: 100.0,
detalhesCargo: detalhesCargoDePedro,
}
fmt.Println(usuario)
}
Neste código, temos a struct DetalhesCargo como um campo da struct Usuario. A saída será:
{Pedro 24 100 {Engenheiro de Software Transporte}}
Para acessar os campos da struct aninhada, utilizamos a mesma sintaxe com o operador ponto, por exemplo:
usuario.detalhesCargo.posicao.
Comparação de Structs
Duas structs são consideradas iguais se todos os seus campos forem iguais (tanto os tipos primitivos quanto os definidos pelo usuário), contudo, nem todos os tipos de dados são comparáveis (mapas, por exemplo, não podem ser comparados diretamente). O exemplo a seguir demonstra como comparar structs:
package main
import (
"fmt"
)
type Usuario struct {
nome string
idade int
saldoBancario float32
}
func main() {
usuario1 := Usuario{
nome: "Pedro",
idade: 24,
saldoBancario: 100.0,
}
usuario2 := Usuario{
nome: "Pedro",
idade: 24,
saldoBancario: 100.0,
}
usuario3 := Usuario{
nome: "Maria",
idade: 21,
saldoBancario: 1000.0,
}
if usuario1 == usuario2 {
fmt.Println("usuario1 e usuario2 são iguais")
} else {
fmt.Println("usuario1 e usuario2 não são iguais")
}
if usuario1 == usuario3 {
fmt.Println("usuario1 e usuario3 são iguais")
} else {
fmt.Println("usuario1 e usuario3 não são iguais")
}
}
Structs vazias e com valor zero são consideradas iguais. A ordem dos campos não importa, o que importa é que cada campo correspondente seja igual. A saída do código acima será:
usuario1 e usuario2 são iguais usuario1 e usuario3 não são iguais
Conclusão
Parabéns!
Agora você possui o conhecimento necessário para utilizar structs em Go. Abordamos todos os aspectos essenciais, desde a declaração e inicialização até o acesso aos campos e comparação de structs. Também exploramos o conceito de estruturas aninhadas. Aqui estão alguns recursos adicionais para aprofundar seu conhecimento sobre structs:
Há muito mais a aprender sobre structs, mas este é um excelente ponto de partida. Esperamos que você tenha aprendido algo novo!
Continue explorando. Continue aprendendo!