Neste segundo artigo da série “Golang para Iniciantes”, vamos mergulhar nos fundamentos da linguagem. Você aprenderá tudo sobre variáveis, tipos de dados, funções, structs e métodos — os blocos de construção essenciais de qualquer programa Go.
Se você ainda não leu o primeiro artigo, recomendamos começar por lá:
📖 ← Artigo Anterior: Golang para Iniciantes: Primeiros Passos
Variáveis em Go
Go oferece várias formas de declarar variáveis, desde a forma explícita até a inferência de tipos.
Declaração Explícita com var
A forma tradicional de declarar variáveis:
package main
import "fmt"
func main() {
// Declaração explícita: var nome tipo = valor
var nome string = "João"
var idade int = 30
var salario float64 = 5000.50
var ativo bool = true
fmt.Printf("Nome: %s, Idade: %d, Salário: %.2f, Ativo: %t\n",
nome, idade, salario, ativo)
}
Declaração com Inferência de Tipo
Go pode inferir o tipo automaticamente:
package main
import "fmt"
func main() {
// Inferência de tipo: var nome = valor (tipo inferido)
var nome = "João" // string
var idade = 30 // int
var preco = 99.99 // float64
var online = true // bool
fmt.Printf("Tipo de nome: %T\n", nome) // string
fmt.Printf("Tipo de idade: %T\n", idade) // int
}
Declaração Curta com :=
A forma mais comum no dia a dia — apenas dentro de funções:
package main
import "fmt"
func main() {
// Forma curta: nome := valor (só funciona dentro de funções)
nome := "João"
idade := 30
pi := 3.14159
fmt.Println(nome, idade, pi)
}
⚠️ Importante: O operador
:=só pode ser usado dentro de funções. Fora de funções (escopo de pacote), usevar.
Declaração Múltipla
Declare várias variáveis de uma vez:
package main
import "fmt"
func main() {
// Múltiplas variáveis do mesmo tipo
var x, y, z int = 1, 2, 3
// Múltiplas variáveis com tipos diferentes
var (
nome string = "Maria"
idade int = 25
ativo bool = true
)
// Com inferência
a, b, c := 1, 2.5, "texto"
fmt.Println(x, y, z, nome, idade, ativo)
fmt.Println(a, b, c)
}
Variáveis Não Inicializadas
Em Go, variáveis sempre têm um “zero value”:
package main
import "fmt"
func main() {
var numero int // 0
var texto string // "" (string vazia)
var booleano bool // false
var ponteiro *int // nil
fmt.Printf("int: %d, string: %q, bool: %t, ponteiro: %v\n",
numero, texto, booleano, ponteiro)
}
Zero values padrão:
| Tipo | Zero Value |
|---|---|
int, float | 0, 0.0 |
string | "" (vazia) |
bool | false |
pointer, slice, map, channel, interface | nil |
struct | Campos com seus zero values |
Constantes com const
Valores que não podem ser alterados:
package main
import "fmt"
func main() {
// Constantes
const pi = 3.14159
const versao = "1.0.0"
const maxUsuarios = 100
// Constantes agrupadas
const (
Segunda = 1
Terca = 2
Quarta = 3
Quinta = 4
Sexta = 5
)
fmt.Println("PI:", pi)
fmt.Println("Dias úteis:", Segunda, Terca, Quarta, Quinta, Sexta)
}
Iota — gerador de constantes incrementais:
package main
import "fmt"
func main() {
const (
Domingo = iota // 0
Segunda // 1
Terca // 2
Quarta // 3
Quinta // 4
Sexta // 5
Sabado // 6
)
fmt.Println("Segunda:", Segunda) // 1
}
Tipos de Dados em Go
Go é uma linguagem estaticamente tipada com tipos básicos claros.
Tipos Numéricos
package main
import "fmt"
func main() {
// Inteiros
var inteiro int = 42 // Plataforma-dependente (32 ou 64 bits)
var int8bit int8 = 127 // -128 a 127
var int16bit int16 = 32767 // -32768 a 32767
var int32bit int32 = 2147483647
var int64bit int64 = 9223372036854775807
// Inteiros sem sinal (unsigned)
var uint8bit uint8 = 255 // 0 a 255
var uint16bit uint16 = 65535
var uint32bit uint32 = 4294967295
var uint64bit uint64 = 18446744073709551615
// Ponto flutuante
var flutuante32 float32 = 3.14159
var flutuante64 float64 = 3.141592653589793
// Números complexos (raramente usados)
var complexo complex64 = 1 + 2i
var complexo128 complex128 = 1 + 2i
fmt.Printf("int: %d (tipo: %T)\n", inteiro, inteiro)
fmt.Printf("float64: %f (tipo: %T)\n", flutuante64, flutuante64)
}
Dica: Use int para inteiros gerais e float64 para ponto flutuante, a menos que tenha requisitos específicos de memória.
Strings
Strings em Go são sequências imutáveis de bytes:
package main
import "fmt"
func main() {
// Declaração de strings
saudacao := "Olá, Mundo!"
citacao := `Esta é uma string
com múltiplas linhas
e "aspas" não precisam ser escapadas`
// Concatenação
nome := "João"
sobrenome := "Silva"
nomeCompleto := nome + " " + sobrenome
// Tamanho
tamanho := len(saudacao)
// Acesso a caracteres (retorna byte)
primeiro := saudacao[0] // 'O' (byte)
fmt.Println(nomeCompleto)
fmt.Println("Tamanho:", tamanho)
fmt.Printf("Primeiro caractere: %c\n", primeiro)
// String como slice de bytes
for i, c := range saudacao {
fmt.Printf("Índice %d: %c\n", i, c)
}
}
Booleanos
package main
import "fmt"
func main() {
var ativo bool = true
inativo := false
// Operações lógicas
resultado1 := ativo && inativo // AND: false
resultado2 := ativo || inativo // OR: true
resultado3 := !ativo // NOT: false
fmt.Println(resultado1, resultado2, resultado3)
}
Operadores
Operadores Aritméticos
package main
import "fmt"
func main() {
a, b := 10, 3
fmt.Println("Soma:", a+b) // 13
fmt.Println("Subtração:", a-b) // 7
fmt.Println("Multiplicação:", a*b) // 30
fmt.Println("Divisão:", a/b) // 3 (divisão inteira)
fmt.Println("Módulo:", a%b) // 1 (resto)
// Incremento e decremento (somente como statements)
a++ // a = a + 1
b-- // b = b - 1
}
Nota: Go não tem operadores de pré/pós-incremento como expressões (
++aou--bnão retornam valores).
Operadores de Comparação
package main
import "fmt"
func main() {
x, y := 5, 10
fmt.Println("Igual:", x == y) // false
fmt.Println("Diferente:", x != y) // true
fmt.Println("Maior:", x > y) // false
fmt.Println("Menor:", x < y) // true
fmt.Println("Maior ou igual:", x >= y) // false
fmt.Println("Menor ou igual:", x <= y) // true
}
Funções
Funções são cidadãs de primeira classe em Go.
Declaração Básica
package main
import "fmt"
// Função simples
func saudar(nome string) {
fmt.Printf("Olá, %s!\n", nome)
}
// Função com retorno
func somar(a, b int) int {
return a + b
}
// Função com múltiplos parâmetros do mesmo tipo
func calcularArea(largura, altura float64) float64 {
return largura * altura
}
func main() {
saudar("Maria")
resultado := somar(10, 20)
area := calcularArea(5.0, 3.0)
fmt.Println("Soma:", resultado)
fmt.Println("Área:", area)
}
Múltiplos Retornos
Uma característica poderosa de Go:
package main
import "fmt"
// Retorna quociente e resto
func dividir(dividendo, divisor int) (int, int) {
quociente := dividendo / divisor
resto := dividendo % divisor
return quociente, resto
}
// Retorna resultado e erro (padrão idiomático)
func dividirSeguro(dividendo, divisor float64) (float64, error) {
if divisor == 0 {
return 0, fmt.Errorf("divisão por zero")
}
return dividendo / divisor, nil
}
func main() {
// Ignorando um retorno com _
q, _ := dividir(17, 5)
fmt.Println("Quociente:", q)
q2, r := dividir(17, 5)
fmt.Printf("%d dividido por %d = %d, resto %d\n", 17, 5, q2, r)
// Tratando erro
resultado, err := dividirSeguro(10.0, 0.0)
if err != nil {
fmt.Println("Erro:", err)
} else {
fmt.Println("Resultado:", resultado)
}
}
Named Return Values
Retornos nomeados tornam o código mais claro:
package main
import "fmt"
// Retornos nomeados
func calcularStats(numeros []int) (min, max, media int) {
if len(numeros) == 0 {
return 0, 0, 0 // Retorna zero values
}
min = numeros[0]
max = numeros[0]
soma := 0
for _, n := range numeros {
if n < min {
min = n
}
if n > max {
max = n
}
soma += n
}
media = soma / len(numeros)
return // Retorna min, max, media automaticamente
}
func main() {
nums := []int{5, 2, 8, 1, 9}
minimo, maximo, media := calcularStats(nums)
fmt.Printf("Min: %d, Max: %d, Média: %d\n", minimo, maximo, media)
}
Funções Variádicas
Aceitam número variável de argumentos:
package main
import "fmt"
// Função variádica
func somarTudo(numeros ...int) int {
total := 0
for _, n := range numeros {
total += n
}
return total
}
func main() {
fmt.Println(somarTudo(1, 2, 3)) // 6
fmt.Println(somarTudo(10, 20)) // 30
fmt.Println(somarTudo()) // 0
// Passando slice com ...
nums := []int{1, 2, 3, 4, 5}
fmt.Println(somarTudo(nums...)) // 15
}
Funções Anônimas e Closures
package main
import "fmt"
func main() {
// Função anônima atribuída a variável
dobro := func(x int) int {
return x * 2
}
fmt.Println(dobro(5)) // 10
// Closure (função que captura variáveis do escopo)
contador := func() func() int {
count := 0
return func() int {
count++
return count
}
}()
fmt.Println(contador()) // 1
fmt.Println(contador()) // 2
fmt.Println(contador()) // 3
}
Structs (Estruturas)
Structs agrupam campos relacionados:
Declaração e Uso
package main
import "fmt"
type Pessoa struct {
Nome string
Idade int
Email string
Ativo bool
}
func main() {
// Criação de instância
p1 := Pessoa{
Nome: "João Silva",
Idade: 30,
Email: "joao@exemplo.com",
Ativo: true,
}
// Forma curta (ordem dos campos)
p2 := Pessoa{"Maria Santos", 25, "maria@exemplo.com", true}
// Struct parcial (campos omitidos ficam com zero value)
p3 := Pessoa{
Nome: "Pedro",
}
// Acesso aos campos
fmt.Println("Nome:", p1.Nome)
fmt.Println("Idade:", p1.Idade)
// Modificação
p1.Idade = 31
fmt.Println("Nova idade:", p1.Idade)
fmt.Printf("Pessoa 2: %+v\n", p2)
fmt.Printf("Pessoa 3: %+v\n", p3)
}
Structs Aninhados
package main
import "fmt"
type Endereco struct {
Rua string
Cidade string
Estado string
CEP string
}
type Pessoa struct {
Nome string
Idade int
Endereco Endereco // Struct aninhado
}
func main() {
pessoa := Pessoa{
Nome: "Ana Paula",
Idade: 28,
Endereco: Endereco{
Rua: "Av. Brasil, 123",
Cidade: "São Paulo",
Estado: "SP",
CEP: "01000-000",
},
}
fmt.Printf("%s mora em %s, %s\n",
pessoa.Nome,
pessoa.Endereco.Cidade,
pessoa.Endereco.Estado)
}
Ponteiros para Structs
package main
import "fmt"
type Pessoa struct {
Nome string
Idade int
}
// Recebe ponteiro para modificar o original
func fazerAniversario(p *Pessoa) {
p.Idade++ // Não precisa de (*p).Idade, Go faz automaticamente
}
func main() {
p := Pessoa{"João", 30}
fmt.Println("Antes:", p.Idade) // 30
fazerAniversario(&p)
fmt.Println("Depois:", p.Idade) // 31
}
Métodos
Métodos são funções associadas a tipos (especialmente structs):
package main
import "fmt"
type Retangulo struct {
Largura float64
Altura float64
}
// Método com receiver por valor (não modifica o original)
func (r Retangulo) Area() float64 {
return r.Largura * r.Altura
}
// Método com receiver por ponteiro (pode modificar o original)
func (r *Retangulo) Escalar(fator float64) {
r.Largura *= fator
r.Altura *= fator
}
// Método com retorno formatado
func (r Retangulo) String() string {
return fmt.Sprintf("Retângulo %.1f x %.1f", r.Largura, r.Altura)
}
func main() {
ret := Retangulo{Largura: 10, Altura: 5}
fmt.Println(ret.String()) // Retângulo 10.0 x 5.0
fmt.Println("Área:", ret.Area()) // 50
ret.Escalar(2)
fmt.Println("Após escalar:", ret.String()) // Retângulo 20.0 x 10.0
}
Quando Usar Ponteiro vs Valor?
| Use valor (r Retangulo) quando… | Use ponteiro (r *Retangulo) quando… |
|---|---|
| Não precisa modificar o receiver | Precisa modificar o receiver |
| Struct é pequena (copia é barata) | Struct é grande (evita cópia) |
| Thread safety é importante | Performance crítica |
Type Conversion (Conversão de Tipos)
Go não faz conversão implícita — você deve converter explicitamente:
package main
import "fmt"
import "strconv"
func main() {
// Entre tipos numéricos
var i int = 42
var f float64 = float64(i) // Conversão explícita obrigatória
var u uint = uint(i)
// String para número
numStr := "123"
num, _ := strconv.Atoi(numStr) // string → int
num64, _ := strconv.ParseInt(numStr, 10, 64)
// Número para string
str := strconv.Itoa(num) // int → string
strf := strconv.FormatFloat(3.14, 'f', 2, 64)
// String para bytes e vice-versa
texto := "Olá"
bytes := []byte(texto)
texto2 := string(bytes)
fmt.Printf("int: %d, float64: %f, uint: %d\n", i, f, u)
fmt.Printf("Número: %d, String: %s\n", num, str)
fmt.Println(texto2)
}
Exercícios Práticos
Exercício 1: Calculadora de IMC
Crie uma função que calcula o IMC (Índice de Massa Corporal) dados peso e altura.
Ver solução
package main
import "fmt"
func calcularIMC(peso, altura float64) float64 {
return peso / (altura * altura)
}
func classificarIMC(imc float64) string {
switch {
case imc < 18.5:
return "Abaixo do peso"
case imc < 25:
return "Peso normal"
case imc < 30:
return "Sobrepeso"
default:
return "Obesidade"
}
}
func main() {
peso := 70.0
altura := 1.75
imc := calcularIMC(peso, altura)
classificacao := classificarIMC(imc)
fmt.Printf("IMC: %.2f - %s\n", imc, classificacao)
}
Exercício 2: Sistema de Biblioteca
Crie um sistema simples de biblioteca com struct Livro e métodos para emprestar e devolver.
Ver solução
package main
import "fmt"
type Livro struct {
Titulo string
Autor string
Emprestado bool
}
func (l *Livro) Emprestar() error {
if l.Emprestado {
return fmt.Errorf("livro já está emprestado")
}
l.Emprestado = true
return nil
}
func (l *Livro) Devolver() error {
if !l.Emprestado {
return fmt.Errorf("livro não estava emprestado")
}
l.Emprestado = false
return nil
}
func (l Livro) String() string {
status := "Disponível"
if l.Emprestado {
status = "Emprestado"
}
return fmt.Sprintf("%s (por %s) - %s", l.Titulo, l.Autor, status)
}
func main() {
livro := Livro{Titulo: "O Senhor dos Anéis", Autor: "J.R.R. Tolkien"}
fmt.Println(livro)
if err := livro.Emprestar(); err != nil {
fmt.Println("Erro:", err)
} else {
fmt.Println("Livro emprestado com sucesso!")
}
fmt.Println(livro)
}
Exercício 3: Gerenciador de Tarefas
Implemente um gerenciador de tarefas com structs e funções para adicionar, listar e completar tarefas.
Ver solução
package main
import "fmt"
import "time"
type Tarefa struct {
ID int
Titulo string
Completa bool
CriadaEm time.Time
}
type GerenciadorTarefas struct {
tarefas []Tarefa
proxID int
}
func (gt *GerenciadorTarefas) Adicionar(titulo string) Tarefa {
tarefa := Tarefa{
ID: gt.proxID,
Titulo: titulo,
Completa: false,
CriadaEm: time.Now(),
}
gt.tarefas = append(gt.tarefas, tarefa)
gt.proxID++
return tarefa
}
func (gt *GerenciadorTarefas) Completar(id int) bool {
for i := range gt.tarefas {
if gt.tarefas[i].ID == id {
gt.tarefas[i].Completa = true
return true
}
}
return false
}
func (gt GerenciadorTarefas) ListarPendentes() []Tarefa {
var pendentes []Tarefa
for _, t := range gt.tarefas {
if !t.Completa {
pendentes = append(pendentes, t)
}
}
return pendentes
}
func main() {
gt := GerenciadorTarefas{}
gt.Adicionar("Estudar Go")
gt.Adicionar("Fazer exercícios")
gt.Adicionar("Ler documentação")
gt.Completar(0)
fmt.Println("Tarefas pendentes:")
for _, t := range gt.ListarPendentes() {
fmt.Printf("- %s\n", t.Titulo)
}
}
Dicas e Melhores Práticas
1. Nomenclatura
- Use
camelCasepara variáveis e funções privadas - Use
PascalCasepara tipos, funções e variáveis exportadas - Use
SCREAMING_SNAKE_CASEpara constantes
const MAX_SIZE = 100 // Constante exportada
var contador = 0 // Variável privada
func calcular() {} // Função privada
func Calcular() {} // Função exportada (pública)
2. Zero Values são Seus Amigos
Aproveite que Go inicializa variáveis automaticamente:
// Bom: aproveita zero values
var contador int // Começa em 0
var encontrado bool // Começa em false
// Ruim: inicialização desnecessária
contador := 0
encontrado := false
3. Evite Variáveis Globais
Prefira passar dependências como parâmetros:
// Ruim: variável global
var db *sql.DB
func main() {
db = conectarDB()
}
// Bom: injeção de dependência
func main() {
db := conectarDB()
handler := NewHandler(db)
}
4. Trate Erros Explicitamente
Go não tem exceções — verifique erros:
// Ruim: ignorando erro
file, _ := os.Open("dados.txt")
// Bom: tratando erro
file, err := os.Open("dados.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
Próximos Passos
Parabéns! Você domina agora os fundamentos da sintaxe de Go. Continue sua jornada:
Próximo Artigo da Série
📖 Controle de Fluxo em Go: if, switch, loops → — Aprenda a controlar o fluxo de execução com condicionais e loops.
Recursos Recomendados
- 📋 Go Cheatsheet — Referência rápida de toda a sintaxe
- 📚 Effective Go — Guia de estilo oficial
- 🎓 Go by Example — Mais exemplos práticos
- 💬 Comunidade Golang Brasil — Tire dúvidas
Carreira Go
- 💰 Salários Go no Brasil — Quanto ganha um dev Go
- 💼 Vagas Go — Oportunidades atuais no mercado
- 🏢 Empresas que usam Go — 948+ empresas no Brasil
Desafios
- Crie uma calculadora completa com operações básicas
- Implemente um jogo da forca em linha de comando
- Crie um sistema de cadastro de produtos
Artigo anterior: Golang para Iniciantes: Primeiros Passos ←
Próximo artigo: Controle de Fluxo em Go: if, switch, loops →
Última atualização: 09 de fevereiro de 2026
Versão do Go: 1.23