Neste quarto episódio da série sobre a linguagem Go, vamos direto ao ponto em quatro pilares essenciais para qualquer aplicação robusta: estruturas de repetição, funções, structs e mapas.
Nesse artigo vamos dar prosseguimento a nossa Série Go, os tópicos anteriores são:
Aqui você entenderá como Go simplifica o controle de fluxo com seu único loop for
, como modularizar o código com funções, como modelar dados com structs, e como armazenar pares chave-valor com mapas. Essencial para quem quer escrever código limpo, performático e idiomático em Go.
Golang (ou Go) OFERECE APENAS UMA ESTRUTURA DE LOOP: o for
. Não há while
ou do-while
.
Essa simplicidade faz parte da filosofia da linguagem. A seguir, estão os usos e variações do for
em Go.
for i := 0; i < 10; i++ {
fmt.Println(i)
}
while
)i := 0
for i < 10 {
fmt.Println(i)
i++
}
Se omitir a inicialização e o incremento, o
for
age como umwhile
.
for {
// execução contínua
}
Precisa de um
break
para terminar.
Loop com range
. Para iterar sobre arrays, slices, maps, strings ou canais.
nums := []int{1, 2, 3}
for i, v := range nums {
fmt.Println(i, v)
}
m := map[string]int{"a": 1, "b": 2}
for k, v := range m {
fmt.Println(k, v)
}
for i, c := range "gölang" {
fmt.Printf("%d: %c\n", i, c)
}
Palavras-chave de controle
break
: Sai do loop.continue
: Vai para a próxima iteração.goto
: Evitado, mas existe.Exemplo com break
e continue
for i := 0; i < 10; i++ {
if i == 5 {
continue
}
if i == 8 {
break
}
fmt.Println(i)
}
Em Go, funções são blocos de código reutilizáveis que executam uma tarefa específica. Elas são definidas com a palavra-chave func
, e podem retornar múltiplos valores, algo incomum em muitas linguagens.
func nomeDaFuncao(param1 tipo1, param2 tipo2) tipoRetorno {
// corpo da função
}
func soma(a int, b int) int {
return a + b
}
func soma(a, b int) int {
return a + b
}
Go permite múltiplos retornos:
func dividir(dividendo, divisor int) (int, error) {
if divisor == 0 {
return 0, fmt.Errorf("divisão por zero")
}
return dividendo / divisor, nil
}
Os valores de retorno podem ser nomeados:
func operacoes(a, b int) (soma, produto int) {
soma = a + b
produto = a * b
return
}
Aceitam número variável de argumentos:
func somar(nums ...int) int {
total := 0
for _, num := range nums {
total += num
}
return total
}
Funções são cidadãos de primeira classe:
func aplicar(f func(int, int) int, a, b int) int {
return f(a, b)
}
Funções podem capturar variáveis do escopo:
func contador() func() int {
i := 0
return func() int {
i++
return i
}
}
Podem ser usadas diretamente:
resultado := func(a, b int) int {
return a + b
}(2, 3)
Funções podem chamar a si mesmas:
func fatorial(n int) int {
if n == 0 {
return 1
}
return n * fatorial(n-1)
}
Em Go, structs são tipos compostos que agrupam variáveis sob um mesmo nome, permitindo representar entidades com múltiplos atributos. Elas são essenciais para a programação orientada a dados na linguagem, já que Go não tem classes como linguagens OO
tradicionais.
Structs são a base para JSON, XML e comunicação em rede via encoding/json
, etc.
type Pessoa struct {
Nome string
Idade int
}
Essa struct
Pessoa
agrupa dois campos:Nome
eIdade
.
p1 := Pessoa{"João", 30}
p2 := Pessoa{Nome: "Maria", Idade: 25}
p3 := Pessoa{}
p3.Nome = "Carlos"
p3.Idade = 40
fmt.Println(p1.Nome) // João
p2.Idade = 26
Go permite trabalhar com ponteiros para structs, economizando memória e evitando cópias desnecessárias:
p := &Pessoa{Nome: "Ana", Idade: 22}
p.Idade++ // sintaxe simplificada, Go desreferencia automaticamente
func (p Pessoa) Saudacao() string {
return "Olá, " + p.Nome
}
func (p *Pessoa) Envelhecer() {
p.Idade++
}
p := struct {
Nome string
Idade int
}{"Lucas", 28}
Go usa composição em vez de herança:
type Endereco struct {
Rua string
Numero int
}
type Cliente struct {
Pessoa
Endereco
ClienteDesde int
}
Campos embutidos podem ser acessados diretamente:
cliente.Rua
Mapas em Go são estruturas de dados baseadas em chave-valor, semelhantes aos dicionários em Python ou objetos em JavaScript. Eles permitem armazenar, acessar e manipular pares de dados de forma eficiente.
var m map[string]int
m = make(map[string]int)
Ou de forma mais concisa:
m := make(map[string]int)
Também é possível inicializar diretamente com valores:
m := map[string]int{
"apple": 2,
"banana": 5,
}
m["orange"] = 3
val := m["apple"]
val, ok := m["banana"]
if ok {
// chave existe
}
delete(m, "orange")
for key, value := range m {
fmt.Println(key, value)
}
Mapas são estruturas de referência, ou seja, ao passar para funções, você está passando o ponteiro internamente.
func modify(m map[string]int) {
m["new"] = 42
}
sync.Map
ou mecanismos de sincronização (sync.Mutex
) se necessário.O valor zero de um mapa é nil
. Você precisa inicializá-lo com make()
antes de usar.
package main
import "fmt"
func main() {
fruits := map[string]int{
"apple": 10,
"banana": 15,
}
fruits["mango"] = 7
for fruit, qty := range fruits {
fmt.Printf("%s: %d\n", fruit, qty)
}
delete(fruits, "banana")
}
Nsse episódio finalizamos o CORE de Go, a partir dos próximos episódio veremos implementações na prática!