Variáveis e tipos básicos
Em Go, há três jeitos de declarar variáveis. Parece confuso, mas faz sentido:
package main
import "fmt"
func main() {
// JEITO 1: explícito e formal — você diz o tipo.
// Útil quando você quer ser claro ou declarar sem inicializar.
var name string = "Maria"
// JEITO 2: o Go infere o tipo a partir do valor.
// Mais limpo, mesma coisa do jeito 1.
var age = 30
// JEITO 3: o "atalho" — só funciona DENTRO de funções.
// É o jeito mais usado no dia a dia.
city := "São Paulo"
fmt.Println(name, age, city)
}Regra de ouro: dentro de funções, use :=. Fora delas (variáveis globais), use var.
Tipos primitivos que você precisa conhecer
// Números inteiros (com sinal)
var a int = 42 // tamanho depende da plataforma (32 ou 64 bits)
var b int32 = 42 // exatamente 32 bits
var c int64 = 42 // exatamente 64 bits
// Números inteiros (sem sinal — só positivos)
var d uint = 42
// Números decimais
var price float64 = 19.99
// Texto
var msg string = "olá"
// Booleano
var active bool = true
// Byte é apelido para uint8 — usado para dados binários
var b1 byte = 'A' // 65
// Rune é apelido para int32 — representa um caractere Unicode
var letter rune = 'á'rune em vez de char? Porque o mundo não é só ASCII. Um rune representa um code point Unicode inteiro, então emojis e caracteres acentuados funcionam direito.Constantes
const Pi = 3.14159
const AppName = "MeuBackend"
// Bloco de constantes (mais elegante)
const (
StatusActive = "ATIVO"
StatusInactive = "INATIVO"
StatusBanned = "BANIDO"
)Sintaxe básica: o essencial
Condicionais (if)
age := 18
if age >= 18 {
fmt.Println("Maior de idade")
} else if age >= 13 {
fmt.Println("Adolescente")
} else {
fmt.Println("Criança")
}
// Truque idiomático: declarar variável dentro do if.
// "err" só existe dentro deste bloco — escopo limpo!
if err := doSomething(); err != nil {
fmt.Println("Deu erro:", err)
}{} são obrigatórias, mesmo para uma única linha. Isso evita aquele bug clássico do C onde você esquece a chave.Loops (for)
Em Go existe apenas um tipo de loop: o for. Mas ele tem várias formas:
// Forma 1: clássica (igual C, Java, etc)
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// Forma 2: como "while" de outras linguagens
counter := 0
for counter < 5 {
counter++
}
// Forma 3: loop infinito (cuidado!)
for {
fmt.Println("rodando para sempre...")
break // sai do loop
}
// Forma 4: range — o queridinho do Go
names := []string{"Ana", "Bia", "Caio"}
for index, name := range names {
fmt.Printf("Posição %d: %s\n", index, name)
}
// Quando você não precisa do índice, use "_" (underscore)
for _, name := range names {
fmt.Println(name)
}Switch
O switch em Go é mais poderoso que em outras linguagens:
day := "segunda"
switch day {
case "segunda", "terça", "quarta", "quinta", "sexta":
fmt.Println("Dia útil")
case "sábado", "domingo":
fmt.Println("Fim de semana")
default:
fmt.Println("Dia inválido")
}
// Switch sem expressão funciona como if/else if encadeado
age := 25
switch {
case age < 13:
fmt.Println("Criança")
case age < 18:
fmt.Println("Adolescente")
default:
fmt.Println("Adulto")
}switch não cai automaticamente para o próximo caso (não tem aquele break chato que você esquece em outras linguagens). Se quiser cair, use fallthrough.Arrays, Slices e Maps
Arrays (tamanho FIXO)
// Array de 3 inteiros — tamanho FAZ PARTE do tipo
var nums [3]int = [3]int{10, 20, 30}
fmt.Println(nums[0]) // 10Na prática, quase ninguém usa arrays diretamente. Use slices.
Slices (a estrela do show)
Um slice é uma "janela" sobre um array. Tamanho dinâmico, fácil de usar:
// Criando um slice (note: SEM tamanho entre os colchetes)
names := []string{"Ana", "Bia"}
// Adicionando elementos com append
names = append(names, "Caio")
names = append(names, "Diana", "Eva") // pode adicionar vários
fmt.Println(names) // [Ana Bia Caio Diana Eva]
fmt.Println(len(names)) // 5 — quantidade de elementos
// Pegando um pedaço (slicing)
first := names[0:2] // [Ana Bia] — do índice 0 até o 2 (exclusive)
last := names[2:] // [Caio Diana Eva]Maps (dicionários / hash tables)
// Mapa de string para int
ages := map[string]int{
"Ana": 30,
"Bia": 25,
}
// Adicionar / atualizar
ages["Caio"] = 40
// Ler com verificação (padrão idiomático!)
age, exists := ages["Diana"]
if exists {
fmt.Println("Diana tem", age, "anos")
} else {
fmt.Println("Diana não existe no mapa")
}
// Remover
delete(ages, "Ana")
// Iterar
for name, age := range ages {
fmt.Printf("%s tem %d anos\n", name, age)
}Structs: agrupando dados
Uma struct é como um molde para criar objetos com vários campos. Pense numa ficha cadastral:
package main
import "fmt"
// Definimos a "forma" de um Usuário
type User struct {
ID int
Name string
Email string
Active bool
}
func main() {
// Jeito 1: criar nomeando os campos (RECOMENDADO)
u1 := User{
ID: 1,
Name: "Maria Silva",
Email: "maria@email.com",
Active: true,
}
// Jeito 2: criar pela ordem (frágil — não use em produção)
u2 := User{2, "João Souza", "joao@email.com", true}
// Acessar campos com ponto
fmt.Println(u1.Name) // Maria Silva
// Modificar
u1.Email = "maria.nova@email.com"
fmt.Println(u1, u2)
}Structs aninhadas
type Address struct {
Street string
City string
State string
}
type Customer struct {
Name string
Address Address // struct dentro de struct
}
c := Customer{
Name: "Ana",
Address: Address{
Street: "Rua das Flores, 123",
City: "Curitiba",
State: "PR",
},
}
fmt.Println(c.Address.City) // CuritibaFunções
Funções em Go têm uma sintaxe peculiar mas muito clara:
// func NOME(parâmetros) tipoDeRetorno { ... }
func add(a int, b int) int {
return a + b
}
// Quando dois parâmetros têm o mesmo tipo, pode encurtar:
func subtract(a, b int) int {
return a - b
}
// MÚLTIPLOS RETORNOS — uma das características mais legais do Go!
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("divisão por zero")
}
return a / b, nil
}
func main() {
// Chamando uma função que retorna múltiplos valores
result, err := divide(10, 2)
if err != nil {
fmt.Println("Erro:", err)
return
}
fmt.Println("Resultado:", result)
}Métodos: funções "presas" a um tipo
type Rectangle struct {
Width, Height float64
}
// Esta função é um MÉTODO do Rectangle.
// "(r Rectangle)" é o "receiver" — diz a qual tipo o método pertence.
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// Receiver com PONTEIRO permite modificar o struct original
func (r *Rectangle) Double() {
r.Width *= 2
r.Height *= 2
}
func main() {
rect := Rectangle{Width: 3, Height: 4}
fmt.Println(rect.Area()) // 12
rect.Double()
fmt.Println(rect.Area()) // 48
}* no receiver? Use se o método modifica o struct, ou se o struct é grande (evita cópias caras). Na dúvida, use ponteiro — é o padrão da maioria dos projetos sérios.Interfaces: o conceito mais elegante de Go
Interface é a forma como Go faz polimorfismo. Mas calma, é muito mais simples do que parece.
A grande sacada
Em Java/C#, você diz: "Esta classe IMPLEMENTA esta interface" (com a palavra implements).
Em Go: "Se anda como pato e faz quack como pato, então é um pato." Não precisa declarar nada. Se um tipo tem os métodos da interface, ele automaticamente satisfaz a interface.
package main
import "fmt"
// Definimos uma interface: "qualquer coisa que sabe Falar"
type Speaker interface {
Speak() string
}
// Dog tem o método Speak() — então é um Speaker
type Dog struct {
Name string
}
func (c Dog) Speak() string {
return c.Name + " diz: Au au!"
}
// Cat também tem o método Speak() — também é um Speaker
type Cat struct {
Name string
}
func (g Cat) Speak() string {
return g.Name + " diz: Miau!"
}
// Função que aceita QUALQUER coisa que seja Speaker
func makeSpeak(f Speaker) {
fmt.Println(f.Speak())
}
func main() {
rex := Dog{Name: "Rex"}
mia := Cat{Name: "Mia"}
makeSpeak(rex) // Rex diz: Au au!
makeSpeak(mia) // Mia diz: Miau!
}Analogia do mundo real
Pense numa tomada elétrica. A "interface" é o formato dos buracos. Não importa se é uma TV, geladeira ou liquidificador — se o plug encaixa, funciona. Você não precisa "registrar" sua TV como "implementadora da interface tomada".
Interface vazia: interface{} ou any
Como toda interface não exige nada, uma interface sem métodos aceita literalmente qualquer coisa:
// "any" é um apelido para interface{} adicionado no Go 1.18
func display(v any) {
fmt.Println(v)
}
display(42)
display("texto")
display([]int{1, 2, 3})any, perde a segurança de tipos. Prefira interfaces específicas sempre que possível.