Paquetes en Go: Visibilidad, Conv Fit y cómo trabajan los módulos
Introducción
En la comunidad de Go, la forma en la que organizamos el código en paquetes y la convención de visibilidad a través de mayúsculas y minúsculas son pilares que definen la mantenibilidad y la productividad del proyecto. Si sos un programador que está empezando a trabajar con Go o querés afinar страниц tu arquitectura, este artículo es tu guía.
En esta publicación te mostraremos:
- Qué significa realmente un paquete en Go y cómo se relaciona con los modules creados por
go mod. - Cómo el sistema de visibilidad funciona con la primera letra de cada identificador.
- ¿Cuándo usar
import,alias,blank identifierodot import? - Ejemplos prácticos con salida prevista para que puedas ver el comportamiento en tiempo real.
- Errores comunes y buenas prácticas.
El objetivo es que, al final, podés organizar tu código en paquetes claros, entender qué puede exportarse y qué queda privado, y manejar las importaciones sin tropezar con ciclos de dependencias o nombres ocultos.
1. ¿Qué esizy un paquete en Go?
En Go, todo el código forma parte de un package—un conjunto lógico de archivos que comparten un mismo namespace. El nombre del paquete se declara con la palabra clave package al inicio de cada archivo:
package mathutil
func Add(a, b int) int {
return a + b
}Una carpeta que contiene archivos con la misma declaración de paquete constituye un paquete. Cuando compilas, Go crea un binario o una librería que contiene todas las funciones exportadas de ese paquete.
Paquetes y módulos
Con la aparición de go.mod en 2015, Go contribueció a un sistema de modules que permite versionar proyectos completos, no solamente paquetes. Un módulo es básicamente una colección de paquetes que comparten una raíz de importación.
$ go mod init github.com/tuusuario/miproyectoEl archivo go.mod guarda la ruta del módulo (por ejemplo, github.com/tuusuario/miproyecto) y las dependencias externas.
Cuando importás un paquete desde otro paquete, uses esa ruta del módulo como prefijo:
import (
"github.com/tuusuario/miproyecto/mathutil"
)
func main() {
fmt.Println(mathutil.Add(2, 3))
}2. Construyendo un paquete desde cero
Para crear un nuevo paquete, simplemente crea una carpeta dentro del módulo con los archivos Go que lo definen. Por convención, el nombre de la carpeta suele coincidir con el nombre del paquete.
miproyecto/
├── go.mod
├── main.go
└── mathutil/
└── math.goEl archivo math.go contiene la lógica, y main.go la aplicación que la consume.
La función init
Cada paquete puede definir una función init(). Go la ejecuta antes de que el paquete sea usado, ideal para inicializar variables, registrar tipos o configurar estados.
package mathutil
import "fmt"
var InitMsg string
func init() {
InitMsg = "mathutil cargado"
fmt.Println(InitMsg)
}Si se importó mathutil en main.go, al arrancar el binario se imprimirá el mensaje antes de cualquier llamada explícita.
3. Visibilidad: mayúsculas y minúsculas
En Go, la visibilidad de un identificador (función, variable, tipo, constante, etc.) depende únicamente de la primera letra:
- Mayúscula → Exportado: visible fuera del paquete.
- Minúscula → No exportado: privado al paquete.
package mathutil
func ExportedFunc() { // visible
fmt.Println("soy exportada")
}
func unexportedFunc() { // privada
fmt.Println("soy privada")
}Esto elimina la necesidad de palabras clave como public o private. Solo basta con la capitalización.
Tipos personalizados
Los structs, interfaces, y otros tipos siguen la misma regla. Si creás un tipo con mayúscula, todas sus propiedades y métodos siguen la regla de exportación individual.
type Person struct { // exportado
Name string // exportada
age int // privada
}
func (p Person) Greet() string {
return "Hola " + p.Name
}El campo age no será accesible desde fuera del paquete, pero el método Greet sí lo será.
4. Importaciones: alias, underscore y dot
El paquete import permite referenciar código de terceros o internos. Hay varias formas de usarlo, cada una con un propósito.
Alias
Asignar un alias reduce la verbosidad o evita colisiones de nombres.
import (
m "github.com/tuusuario/miproyecto/mathutil"
)
func main() {
fmt.Println(m.Add(5, 7))
}Blank identifier _
El import con _ ejecuta la función init() del paquete sin importar nada de él.
import _ "github.com/tuusuario/miproyecto/mathutil"Esto se usa comúnmente Smokers para registrar drivers de bases de datos.
Dot import .
Con . podes usar todas las exportaciones del paquete sin prefijo, aunque se recomienda con cuidado por la contaminación de namespace.
import . "github.com/tuusuario/miproyecto/mathutil"
func main() {
fmt.Println(Add(10, 20)) // Add sin paquete
}5. Ejemplo práctico: paquete stringutil
Creemos un paquete que ofrece funciones sobre strings.
stringutil/
├── stringutil.go
└── stringutil_test.gopackage stringutil
// Reverse devuelve el string invertido.
func Reverse(s string) string {
runes := []rune(s)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
// private helper
func isVowel(c rune) bool {
switch c {
case 'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U':
return true
}
return false
}Uso en main
package main
import (
"fmt"
"github.com/tuusuario/miproyecto/stringutil"
)
func main() {
original := "GoLang"
fmt.Println("Original:", original)
fmt.Println("Invertido:", stringutil.Reverse(original))
}Salida esperada:
Original: GoLang
Invertido: gnaloG6. Error común: importación cíclica
Si el paquete A importa a B, y B a A, Go generará error: import cycle not allowed.
// A.go
package a
import "github.com/tuusuario/miproyecto/b"
func FuncA() {}
// B.go
package b
import "github.com/tuusuario/miproyecto/a"
func FuncB() {}Para resolverlo, extraí las dependencias comunes en un paquete intermedio o usá interfaces.
7. Build tags y archivos condicionales
Go permite compilar archivos condicionalmente con build tags.
// +build windows
package mypkg
func OSName() string { return "Windows" }Al compilar en Linux, este archivo no se incluye, evitando incompatibilidades.
8. Buenas prácticas de visibilidad
- Exporta solo lo necesario: mantener la superficie pública lo más pequeña reduce la complejidad.
- Capitaliza el nombre del paquete:
mathutilen minúscula por convención, pero el nombre del paquete no afecta visibilidad. - Usa comentarios de exportación: Los comentarios que siguen la forma
// Funciónson tratados porgodocy deben ser claros. - Evita dot imports: salvo en paquetes de prueba como
testing. - Controlá las dependencias externas: con
go mod tidymantén solo las que realmente usás.
9. Errores frecuentes y cómo evitarlos
| Error | Causa | Solución |
|---|---|---|
undefined: <func> |
No exportado o no importado | Cambiar la primera letra a mayúscula o importarlo correctamente |
| Import cycle | Dependencia circular | Crear paquete intermedio o usar interfaces |
go: cannot find module |
go mod no inicializado |
Ejecutar go mod init y go mod tidy |
Mensajes de imported and not used |
Importación sin uso | Borrar o usar la importación |
10. Conclusión
Los paquetes участвando en Go son más que un simple agrupamiento de archivos; son la forma de modularizar tu código, definir su visibilidad y manejar dependencias de formanpj. La convención de mayúscula/minúscula hace que la visibilidad sea explícita y libre de palabras clave. Con la herramienta de modules y los build tags, tenés un control fino sobre cómo y cuándo se compila cada parte.
gren
Próximos pasos: probar la creación de un paquete con init que registre un logger, usar alias para evitar colisionesлаһ, y explorar el uso de build tags para compilar código que varíe según la arquitectura.
¡Suerte y que el código siga fluyendo!
DUGLAS MORENO
Comentarios (0)
Sé el primero en comentar.