Paquetes y Modulos
Paquetes y Modulos
Paquetes en Go
Un paquete es una coleccion de archivos .go en el mismo directorio. Todos los archivos de un directorio deben pertenecer al mismo paquete.
// archivo: saludos/hola.go
package saludos
func Hola(nombre string) string {
return "Hola, " + nombre
}
func despedida(nombre string) string {
return "Adios, " + nombre
}
// archivo: main.go
package main
import (
"fmt"
"mi-proyecto/saludos"
)
func main() {
fmt.Println(saludos.Hola("Go")) // funciona: Hola es exportada
// fmt.Println(saludos.despedida("Go")) // ERROR: despedida no es exportada
}
Visibilidad: mayuscula = exportado
La regla de visibilidad en Go es la mas simple de cualquier lenguaje:
| Nombre | Visibilidad | Ejemplo |
|---|---|---|
| Inicia con mayuscula | Exportado (publico) | Println, Config, HTTPClient |
| Inicia con minuscula | No exportado (privado al paquete) | helper, config, parseURL |
Esto aplica a todo: funciones, tipos, constantes, variables y campos de struct.
package usuario
type Usuario struct {
Nombre string // exportado: accesible desde otros paquetes
Email string // exportado
edad int // no exportado: solo accesible dentro del paquete
}
func Nuevo(nombre, email string, edad int) Usuario {
return Usuario{
Nombre: nombre,
Email: email,
edad: edad,
}
}
func (u Usuario) EsMayorDeEdad() bool {
return u.edad >= 18 // accede a campo privado dentro del paquete
}
Go Modules
Crear un modulo
mkdir mi-proyecto && cd mi-proyecto
go mod init github.com/usuario/mi-proyecto
Esto genera go.mod:
module github.com/usuario/mi-proyecto
go 1.22
go.mod y go.sum
| Archivo | Proposito |
|---|---|
go.mod | Declara el modulo, version de Go y dependencias directas |
go.sum | Checksums de todas las dependencias (directas e indirectas) |
// go.mod
module github.com/usuario/mi-proyecto
go 1.22
require (
github.com/gin-gonic/gin v1.9.1
github.com/joho/godotenv v1.5.1
)
Nunca edites go.sum manualmente. Se genera automaticamente.
Comandos esenciales
# Agregar una dependencia
go get github.com/gin-gonic/gin@latest
# Agregar una version especifica
go get github.com/gin-gonic/[email protected]
# Eliminar dependencias no usadas y agregar las faltantes
go mod tidy
# Descargar dependencias al cache local
go mod download
# Verificar integridad de dependencias
go mod verify
# Ver el grafo de dependencias
go mod graph
# Copiar dependencias a un directorio vendor
go mod vendor
Versionado semantico
Go Modules usa semver para las versiones:
v1.2.3
│ │ │
│ │ └── Patch: correcciones sin romper API
│ └──── Minor: nuevas funcionalidades sin romper API
└────── Major: cambios que rompen API
Regla importante en Go: las versiones v2+ cambian el import path:
import "github.com/usuario/libreria" // v0.x o v1.x
import "github.com/usuario/libreria/v2" // v2.x
import "github.com/usuario/libreria/v3" // v3.x
Paquete main y func init()
Paquete main
El paquete main es especial: define un ejecutable. Debe contener una funcion main():
package main
func main() {
// punto de entrada del programa
}
Un modulo puede tener multiples ejecutables:
mi-proyecto/
├── cmd/
│ ├── servidor/
│ │ └── main.go // package main
│ └── cli/
│ └── main.go // package main
├── internal/
│ └── ...
└── go.mod
Funcion init()
init() se ejecuta automaticamente antes de main(). Cada archivo puede tener multiples init():
package main
import "fmt"
var config string
func init() {
config = "produccion"
fmt.Println("init: configurando")
}
func main() {
fmt.Println("main: config =", config)
}
// init: configurando
// main: config = produccion
Orden de ejecucion:
- Se inicializan las variables de paquete
- Se ejecutan las funciones
init()de cada archivo (orden alfabetico de archivos) - Se ejecuta
main()
Usa init() con moderacion. Dificulta el testing y oculta dependencias. Prefiere inicializacion explicita.
Internal packages
El directorio internal restringe la visibilidad de paquetes. Solo el paquete padre y sus hijos pueden importar paquetes dentro de internal:
mi-proyecto/
├── internal/
│ ├── auth/ # solo mi-proyecto puede importar
│ │ └── auth.go
│ └── database/ # solo mi-proyecto puede importar
│ └── db.go
├── pkg/
│ └── utils/ # cualquiera puede importar
│ └── utils.go
└── main.go
// main.go - FUNCIONA
import "mi-proyecto/internal/auth"
// otro-proyecto/main.go - ERROR de compilacion
import "mi-proyecto/internal/auth"
// use of internal package mi-proyecto/internal/auth not allowed
Estructura de proyecto recomendada
mi-proyecto/
├── cmd/ # Ejecutables
│ └── api/
│ └── main.go
├── internal/ # Codigo privado del modulo
│ ├── handler/
│ │ └── usuario.go
│ ├── service/
│ │ └── usuario.go
│ └── repository/
│ └── usuario.go
├── pkg/ # Codigo reutilizable publico
│ └── validator/
│ └── validator.go
├── go.mod
├── go.sum
└── README.md
| Directorio | Proposito |
|---|---|
cmd/ | Un subdirectorio por ejecutable |
internal/ | Paquetes privados, no importables externamente |
pkg/ | Paquetes publicos, reutilizables por otros proyectos |
Go Workspace (go.work)
Para trabajar con multiples modulos locales sin publicar:
mkdir workspace && cd workspace
go work init ./modulo-a ./modulo-b
Genera go.work:
go 1.22
use (
./modulo-a
./modulo-b
)
Esto permite que modulo-b importe modulo-a sin necesidad de publicarlo:
// modulo-b/main.go
package main
import "github.com/usuario/modulo-a/utils"
func main() {
utils.HacerAlgo()
}
Comandos de workspace:
# Agregar un modulo al workspace
go work use ./nuevo-modulo
# Sincronizar dependencias
go work sync
No subas go.work al repositorio. Es para desarrollo local.
Imports agrupados
Go tiene una convencion para organizar imports:
import (
// Stdlib
"fmt"
"net/http"
// Dependencias externas
"github.com/gin-gonic/gin"
"github.com/joho/godotenv"
// Paquetes internos del proyecto
"mi-proyecto/internal/handler"
"mi-proyecto/internal/service"
)
Alias de imports:
import (
"fmt"
// Alias para evitar conflictos
mifmt "mi-proyecto/pkg/fmt"
// Import solo por side effects (init)
_ "github.com/lib/pq"
// Import embebido (dot import, evitalo)
// . "fmt"
)
Resumen
- Los paquetes agrupan codigo; la mayuscula inicial define visibilidad
go mod initcrea un modulo;go mod tidysincroniza dependenciasgo.sumgarantiza integridad; nunca lo edites manualmenteinternal/protege paquetes de importacion externainit()se ejecuta antes demain()pero usalo con moderaciongo.workfacilita desarrollo local con multiples modulos- Organiza:
cmd/para ejecutables,internal/para codigo privado,pkg/para codigo publico