Pacotes
Esta aula explica o sistema de pacotes em Go, cobrindo a declaração de pacotes, regras de visibilidade baseadas em letras maiúsculas/minúsculas, a sintaxe de importação e a organização de código em múltiplos arquivos e diretórios.
Pacotes são a unidade fundamental de organização e reutilização de código em Go. Todo arquivo fonte pertence a um pacote, e a estrutura de pacotes define o escopo de nomes, a visibilidade de identificadores e a modularidade do programa. Nesta aula, você aprenderá como declarar pacotes, controlar a exportação de símbolos, importar dependências e organizar projetos de forma eficiente.
Diferente de linguagens como Java ou Python, Go não possui classes nem herança; a modularidade é alcançada através de pacotes e interfaces. Compreender bem o sistema de pacotes é essencial para escrever código limpo, reutilizável e de fácil manutenção.
package
Todo arquivo Go começa com uma declaração package que define a qual pacote ele pertence. A declaração deve ser a primeira linha do arquivo (antes de qualquer importação). O nome do pacote geralmente é o mesmo nome do diretório onde o arquivo está localizado, seguindo a convenção de usar letras minúsculas e sem underscores (a menos que o nome seja composto, como net/http).
Exemplos de declaração de pacote:
package main
func main() {
println("Olá, mundo!")
}O pacote main é especial: ele define um executável independente. Pacotes com outros nomes são bibliotecas que podem ser importadas por outros pacotes.
Visibilidade (maiúscula/minúscula)
Em Go, a visibilidade de um identificador (variável, função, tipo, constante) é determinada pela primeira letra do seu nome. Se a primeira letra for maiúscula, o identificador é exportado (público), visível fora do pacote. Se for minúscula, é não exportado (privado), visível apenas dentro do mesmo pacote.
Exemplo:
package matematica
// Soma é exportada (maiúscula)
func Soma(a, b int) int {
return a + b
}
// subtrai não é exportada (minúscula)
func subtrai(a, b int) int {
return a - b
}Essa regra simples evita a necessidade de palavras-chave como public ou private. O escopo de um identificador não exportado é o pacote inteiro, ou seja, todos os arquivos que declaram o mesmo pacote podem acessá-lo.
import
Para usar funcionalidades de outros pacotes, utilizamos a declaração import. Ela pode importar um ou mais pacotes, listando seus caminhos entre aspas duplas. O caminho é relativo ao módulo (definido no go.mod) ou ao GOPATH.
Exemplo de importação:
package main
import (
"fmt"
"matematica"
)
func main() {
fmt.Println(matematica.Soma(3, 4))
}Go permite importar pacotes com alias para evitar conflitos de nomes:
import (
"fmt"
m "matematica"
)
func main() {
fmt.Println(m.Soma(3, 4))
}Também é possível importar pacotes apenas para executar suas funções init usando o identificador em branco (_):
import _ "image/png" // registra o decodificador PNGOrganização
Go incentiva uma estrutura de diretórios simples: cada diretório representa um pacote, e todos os arquivos .go dentro desse diretório devem declarar o mesmo nome de pacote. Subdiretórios podem representar subpacotes, mas não há herança de visibilidade entre eles.
Exemplo de estrutura de projeto:
meuprojeto/
├── go.mod
├── main.go (package main)
├── matematica/
│ ├── soma.go (package matematica)
│ └── subtracao.go (package matematica)
└── utils/
└── strings.go (package utils)No main.go, importamos meuprojeto/matematica e meuprojeto/utils. A importação usa o módulo como prefixo. É boa prática manter os pacotes coesos e com responsabilidades únicas, evitando pacotes muito grandes ou com muitos arquivos.
Boas práticas: Use nomes curtos e descritivos para pacotes; evite nomes genéricos como util ou common. Prefira nomes que indiquem o domínio, como http, json, time. Também é recomendado não usar underscores nos nomes de pacotes, a menos que seja necessário (ex.: net/http é um pacote composto, mas o nome do diretório é http dentro de net).
Referências
- Effective Go - Packages
- Go Language Specification - Packages
- How to Write Go Code
- Go Standard Library
- Package names - Go Blog
Exercícios
- Crie um pacote chamado
calculadoracom uma função exportadaSomae uma função não exportadasubtrai. Em seguida, escreva um programamainque importa o pacote e chamaSoma. - Explique por que a função
subtrainão pode ser chamada de fora do pacotecalculadora. - Escreva um programa que importe o pacote
fmtusando um alias parafe imprima "Olá" usandof.Println. - Qual a diferença entre importar um pacote com o identificador em branco (
_) e importá-lo normalmente? - Dada a estrutura de diretórios:
projeto/main.goeprojeto/meupacote/arquivo.go, qual deve ser a declaração de pacote emarquivo.goe como importá-lo emmain.go?
calculadora com um arquivo calculadora.go:package calculadora
func Soma(a, b int) int {
return a + b
}
func subtrai(a, b int) int {
return a - b
}No main.go no diretório raiz:package main
import (
"fmt"
"meuprojeto/calculadora"
)
func main() {
fmt.Println(calculadora.Soma(2, 3))
}subtrai começa com letra minúscula, o que a torna não exportada (privada) ao pacote. Apenas identificadores com primeira letra maiúscula são exportados e visíveis fora do pacote.package main
import f "fmt"
func main() {
f.Println("Olá")
}_ faz com que o pacote seja compilado e tenha suas funções init executadas, mas os identificadores do pacote não ficam acessíveis no código. É usado para efeitos colaterais, como registrar drivers de banco de dados. Já a importação normal torna os identificadores exportados disponíveis.arquivo.go: package meupacote. Em main.go, supondo que o módulo se chame projeto, a importação será: import "projeto/meupacote".