Pacotes
Esta aula aborda o sistema de pacotes em Go, incluindo declaração de pacotes, visibilidade de identificadores, importação de pacotes e organização de código. Você aprenderá a estruturar projetos Go de forma modular e reutilizável.
Em Go, pacotes são a unidade fundamental de organização e reutilização de código. Todo arquivo .go pertence a um pacote, e a estrutura de diretórios reflete a hierarquia de pacotes. Compreender como declarar, importar e controlar a visibilidade de identificadores é essencial para escrever código limpo, modular e de fácil manutenção.
Nesta aula, exploraremos os conceitos de package, visibilidade baseada em letras maiúsculas/minúsculas, a declaração import e as boas práticas de organização de código em Go. Ao final, você será capaz de criar pacotes próprios e utilizá-los em seus projetos.
package
Todo código Go começa com a declaração package nome, que define a qual pacote o arquivo pertence. O pacote main é especial: ele indica que o programa é executável e deve conter uma função main(). Pacotes com outros nomes são bibliotecas ou partes de um programa maior.
A declaração package deve ser a primeira linha do arquivo (apenas comentários podem vir antes). O nome do pacote geralmente é o mesmo nome do diretório onde o arquivo está, mas não é obrigatório – é uma convenção forte. Por exemplo, arquivos no diretório math/ costumam ter package math.
// arquivo: calculadora/soma.go
package calculadora
func Soma(a, b int) int {
return a + b
}
No exemplo acima, o pacote é calculadora e a função Soma é exportada (visível fora do pacote) porque começa com letra maiúscula.
Visibilidade (maiúscula/minúscula)
Go não possui as palavras-chave public, protected ou private. Em vez disso, a visibilidade de um identificador (função, variável, constante, tipo, struct, interface, etc.) é determinada pela primeira letra do seu nome:
- Letra maiúscula: o identificador é exportado (público), visível para outros pacotes.
- Letra minúscula: o identificador é não exportado (privado), visível apenas dentro do mesmo pacote.
Essa regra se aplica a todos os níveis: pacote, struct, método, campo de struct, etc. Por exemplo, em um pacote banco:
package banco
// Exportado
type Conta struct {
Saldo float64 // exportado (maiúsculo)
titular string // não exportado (minúsculo)
}
// Exportado
func NovaConta(saldoInicial float64) *Conta {
return &Conta{Saldo: saldoInicial, titular: "Anônimo"}
}
// Não exportado
func validarSaldo(valor float64) bool {
return valor >= 0
}
Fora do pacote banco, só podemos acessar Conta, NovaConta e o campo Saldo. O campo titular e a função validarSaldo são inacessíveis.
import
Para usar código de outro pacote, utilizamos a declaração import. Ela pode importar um ou mais pacotes, e cada caminho é uma string entre aspas duplas. O caminho é relativo ao módulo (definido no go.mod).
package main
import (
"fmt"
"meuprojeto/calculadora"
)
func main() {
resultado := calculadora.Soma(3, 4)
fmt.Println("Resultado:", resultado)
}
Se o nome do pacote importado conflitar com outro, podemos usar um alias:
import (
cr "crypto/rand"
mr "math/rand"
)
Também é possível importar apenas para efeitos colaterais (inicialização) usando _ como alias:
import _ "image/png" // registra o decodificador PNG
Pacotes da biblioteca padrão não precisam de caminho relativo ao módulo; são referenciados pelo nome simples (ex: "fmt", "net/http").
Organização
Go incentiva uma organização simples: um diretório para cada pacote, e o nome do diretório coincide com o nome do pacote. Dentro de um diretório, múltiplos arquivos .go podem pertencer ao mesmo pacote, e eles compartilham o mesmo namespace (não pode haver conflito de nomes exportados ou não exportados entre arquivos do mesmo pacote).
Exemplo de estrutura de projeto:
meuprojeto/
├── go.mod
├── main.go
└── calculadora/
├── soma.go
└── subtracao.go
main.go pertence ao pacote main; soma.go e subtracao.go pertencem ao pacote calculadora (declarado em cada arquivo como package calculadora).
Boas práticas:
- Evite pacotes com muitos arquivos; se um pacote ficar grande, considere dividi-lo em subpacotes.
- Nomeie pacotes com nomes curtos, em minúsculas, sem underscores ou mixedCaps (ex:
http,json,ioutil). - Não crie pacotes com nomes genéricos como
utilsoucommon; prefira nomes descritivos.
Boas práticas adicionais
Sempre use go fmt para formatar o código automaticamente. Evite dependências cíclicas entre pacotes. Utilize o comando go vet para verificar problemas comuns. Para testes, crie arquivos *_test.go no mesmo diretório do pacote.
Referências
- Effective Go - Packages
- Go Language Specification - Packages
- How to Write Go Code - Organization
- Go Standard Library
- Package names - Go Blog
Exercícios
Crie um pacote chamado
conversoescom funções exportadas para converter Celsius para Fahrenheit e vice-versa. Escreva um programa main que use essas funções.✓ Resposta:// conversoes/conversoes.go package conversoes func CelsiusParaFahrenheit(c float64) float64 { return c*9/5 + 32 } func FahrenheitParaCelsius(f float64) float64 { return (f - 32) * 5 / 9 }// main.go package main import ( "fmt" "meuprojeto/conversoes" ) func main() { fmt.Println("30°C em Fahrenheit:", conversoes.CelsiusParaFahrenheit(30)) fmt.Println("86°F em Celsius:", conversoes.FahrenheitParaCelsius(86)) }No pacote
conversoesdo exercício anterior, adicione uma função não exportadaarredondarque arredonda um float para duas casas decimais. Use-a dentro das funções exportadas.✓ Resposta:package conversoes import "math" func arredondar(valor float64) float64 { return math.Round(valor*100) / 100 } func CelsiusParaFahrenheit(c float64) float64 { return arredondar(c*9/5 + 32) } func FahrenheitParaCelsius(f float64) float64 { return arredondar((f - 32) * 5 / 9) }Explique por que o seguinte código não compila e corrija-o:
package main; import "fmt"; func main() { fmt.Println(MinhaFuncao()) }; func MinhaFuncao() int { return 42 }✓ Resposta: O código compila normalmente, pois a funçãoMinhaFuncaocomeça com maiúscula e está no mesmo pacotemain. Não há erro. Se houver erro, pode ser devido a falta de chaves ou ponto e vírgula. O código está correto.Crie um pacote
validacaocom uma função exportadaEmailValido(email string) boolque verifica se o email contém '@' e '.'. Em seguida, importe e use no main.✓ Resposta:// validacao/validacao.go package validacao import "strings" func EmailValido(email string) bool { return strings.Contains(email, "@") && strings.Contains(email, ".") }// main.go package main import ( "fmt" "meuprojeto/validacao" ) func main() { fmt.Println(validacao.EmailValido("teste@exemplo.com")) // true fmt.Println(validacao.EmailValido("invalido")) // false }Reorganize o projeto abaixo para seguir as convenções Go:
projeto/contémmain.go(pacote main) e um arquivoutils/helpers.gocompackage auxiliar. Corrija os nomes de pacote e imports.✓ Resposta: O diretórioutils/deve conter arquivos compackage utils(mesmo nome do diretório). Renomeie o pacote parautilse ajuste o import emmain.gopara"projeto/utils". Exemplo:// utils/helpers.go package utils func Ajuda() string { return "Ajuda!" }// main.go package main import ( "fmt" "projeto/utils" ) func main() { fmt.Println(utils.Ajuda()) }