← Volver al listado de tecnologías

Paquetes y Modulos

Por: Artiko
gopaquetesmodulosgo-mod

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:

NombreVisibilidadEjemplo
Inicia con mayusculaExportado (publico)Println, Config, HTTPClient
Inicia con minusculaNo 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

ArchivoProposito
go.modDeclara el modulo, version de Go y dependencias directas
go.sumChecksums 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:

  1. Se inicializan las variables de paquete
  2. Se ejecutan las funciones init() de cada archivo (orden alfabetico de archivos)
  3. 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
DirectorioProposito
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