CodeGym /Cursos /Go SELF /Imports — agrupacion, alias y

Imports — agrupacion, alias y _import

Go SELF
Nivel 10 , Lección 3
Disponible

1. Para que sirve import y por que Go prohibe lo innecesario

Cuando escribes un programa, casi siempre usas codigo ajeno: impresion, parseo de numeros, trabajo con cadenas, numeros aleatorios, tiempo y asi sucesivamente. En Go esto se hace mediante import: le dices explicitamente al compilador que paquetes necesita un archivo concreto. Esto es importante: el import no es “para todo el proyecto”, sino para el archivo, y Go lo trata con rigor.

Ese rigor se manifiesta en que los imports no utilizados estan prohibidos. No “no se recomienda”, no “bueno, vale”, sino directamente “no”. Esta es una de las formas en que Go nos obliga a mantener limpias las dependencias. Si un paquete no se usa, significa o que no lo necesitas, o que olvidaste escribir el codigo que lo utiliza. Y mejor descubrirlo de inmediato que dentro de un mes.

Mini ejemplo: el clasico “hello world” con el import de fmt.

package main

import "fmt"

func main() {
	fmt.Println("Hello!") // Hello!
}

Y ahora el error tipico de principiante: “lo importo para mas adelante”.

package main

import (
	"fmt"
	"math" // <- not used
)

func main() {
	fmt.Println("Hi")
}

Ese codigo no compila: el compilador dira algo parecido a "imported and not used: math". Eso es normal. Go esta cuidando de tu futuro “yo”, que leera el codigo e intentara entender que necesita realmente el programa.

2. Formas y orden de los imports

Import individual y agrupado import

Los imports en Go tienen dos formas principales: individual y agrupada. Y ambas son totalmente equivalentes: no se trata de “correcto/incorrecto”, sino de legibilidad. Cuando hay un solo paquete, la forma individual resulta la mas simple. Cuando hay dos o mas, casi siempre es mas comodo agruparlos.

Import individual:

package main

import "fmt"

func main() {
	fmt.Println("one import") // one import
}

Import agrupado:

package main

import (
	"fmt"
	"strconv"
)

func main() {
	fmt.Println(strconv.Itoa(2026)) // 2026
}

En la practica, el import agrupado es el estilo “por defecto” en cuanto las dependencias son mas de una. Se amplía con facilidad: añades lineas dentro de los parentesis y no piensas en el formato.

Dependencias conscientes y legibilidad

Cuando empiezas a escribir programas mas grandes, los imports se convierten en tu mini mapa: por ellos se ve de que se ocupa el archivo. Si ves fmt, strconv, strings, parece trabajo con texto y salida. Si ves net/http, cerca habra un servidor. Si ves time, significa que se trata de tiempo o timeouts.

Por eso conviene tratar los imports como un “escaparate” del archivo. Si el escaparate esta abarrotado, lo mas probable es que dentro tambien reine el desorden.

Hay varios principios muy practicos que puedes seguir incluso siendo principiante, sin guerras religiosas sobre el estilo.

  • Mejor mantener los imports en orden alfabetico, al menos dentro de la biblioteca estandar.
  • No conviene importar un paquete “por si acaso” — Go de todos modos no lo permitira.
  • Si borraste el codigo que usaba un paquete y el compilador empezo a quejarse, es una pista: elimina la dependencia.

Un pequeño esquema logico:

Añadiste una linea import -> tomaste una dependencia
Tomaste una dependencia -> complicaste el archivo
Complicaste el archivo -> la lectura se volvio mas pesada
Entonces -> el import debe ser consciente

En este momento Go recuerda a un profesor estricto: “quita lo innecesario, por favor”.

3. Mini tasker: entrenamos imports limpios

Para que los ejemplos no se queden desconectados de la vida real, vamos a seguir con la misma aplicacion educativa. Que sea una pequeña utilidad de consola “mini tasker”: lee el titulo de una tarea e imprime el titulo normalizado y un “pseudo ID”.

En nuestro nivel actual (sin slices ni structs) sera un programa sencillo, pero ya resulta util como entrenamiento para codigo e imports limpios.

Version 1: leemos una cadena e imprimimos tal cual

Aqui solo necesitamos fmt.

package main

import "fmt"

func main() {
	var title string
	fmt.Scan(&title)

	fmt.Println("task:", title) // for example: task: BuyMilk
}

Pero pronto se vera que la entrada mediante Scan “corta” la cadena por los espacios. El usuario queria "Buy milk", y obtuvo "Buy". Por ahora lo dejaremos asi (hablaremos de la entrada avanzada mas adelante), y ahora añadiremos una normalizacion sencilla: recortaremos los espacios al principio y al final y haremos una “etiqueta bonita”.

Version 2: añadimos strings y un import agrupado

package main

import (
	"fmt"
	"strings"
)

func main() {
	var title string
	fmt.Scan(&title)

	title = strings.TrimSpace(title)
	fmt.Println("task:", title) // task: BuyMilk
}

Tenemos dos paquetes, y el import agrupado encaja de forma natural.

Version 3: juntamos todo

Ahora montemos el “mini tasker” de una forma un poco mas agradable: normalizamos la entrada, hacemos un “ID” como numero (aunque sea simple) y mostramos el resultado.

Aqui aparecera strings y strconv. Dos paquetes, asi que los agrupamos.

package main

import (
	"fmt"
	"strconv"
	"strings"
)

func main() {
	var raw string
	fmt.Scan(&raw)

	title := strings.TrimSpace(raw)
	id := strconv.Itoa(len(title))

	fmt.Println("id:", id, "task:", title) // id: 7 task: BuyMilk
}

Si, “ID por longitud de la cadena” no es un sistema real de identificadores. Pero para nuestro nivel actual es una forma excelente de practicar: los imports estan limpios, todos se usan, la logica es pequeña y el programa no se rompe.

4. Alias de imports: cuando realmente hacen falta

A veces el nombre del paquete no es comodo en un archivo concreto. O has importado dos paquetes cuyos “ultimos nombres” son iguales y quieres distinguirlos claramente en el codigo. O quieres evitar un conflicto de nombres. Para eso existe el alias de import: puedes renombrar un paquete dentro de un solo archivo.

La sintaxis es esta:

import f "fmt"

Y entonces, en vez de fmt.Println, escribes f.Println. Funciona, pero es importante entender que el alias no es un adorno. Si empiezas a acortar todo sin criterio, el codigo empezara a parecer criptografia (y aun no estamos estudiando criptografia, como mucho, la moral).

Alias por legibilidad: con cuidado

package main

import (
	"fmt"
	s "strings"
)

func main() {
	var title string
	fmt.Scan(&title)

	title = s.TrimSpace(title)
	fmt.Println("task:", title) // task: BuyMilk
}

Eso se puede hacer, pero la pregunta es: ¿se ha vuelto mas claro? Para un principiante, normalmente es al reves: strings.TrimSpace se lee mas facil que s.TrimSpace. Los alias conviene usarlos cuando hay una razon real.

Conflicto de nombres: crypto/rand vs math/rand

Una situacion muy real: dos paquetes quieren llamarse igual en el codigo. El ejemplo clasico es crypto/rand y math/rand. Ambos son “rand”, pero su significado es distinto: uno sirve para criptografia y el otro para la pseudoaleatoriedad normal. Aunque todavia no uses ambos, es importante saber leer ese codigo.

package main

import (
	crand "crypto/rand"
	"fmt"
	mrand "math/rand"
)

func main() {
	_ = crand.Reader // only to show that the package exists
	fmt.Println(mrand.Intn(10)) // 0..9 (example)
}

Aqui los alias hacen el codigo honesto: crand y mrand son cosas distintas, y eso se ve a simple vista.

Alias contra shadowing

Existe un error curioso (y muy molesto): importaste un paquete y luego, por accidente, llamaste a una variable igual que el paquete. Eso se llama shadowing: un nombre dentro de un alcance interno oculta uno externo.

Por ejemplo:

package main

import "fmt"

func main() {
	fmt.Println("before") // before

	fmt := "oops"
	_ = fmt

	// fmt.Println("after") // will not compile
}

Dentro de main, el nombre fmt se ha convertido en una variable de tipo string, y ya no se puede acceder al paquete fmt.

¿Como vivir con eso? Primero, no llames a las variables como los paquetes. Segundo, si el conflicto es inevitable (poco frecuente, pero puede pasar), un alias de import puede salvarte.

package main

import f "fmt"

func main() {
	fmt := "still ok"
	_ = fmt

	f.Println("package still available") // package still available
}

Este es un ejemplo donde el alias no es “estetica”, sino realmente una “tabla de salvacion”.

5. _-import: conectamos un paquete por la inicializacion

Existe una forma especial de import que parece rara, pero aparece en proyectos reales:

import _ "some/package"

Ese import se llama blank import. La idea es que importas el paquete, pero no introduces su nombre en el codigo. Es decir, no podras escribir pkg.Something, porque pkg no existe en tu archivo. Entonces, ¿para que sirve?

En lenguaje humano: “no necesito las funciones/tipos de ese paquete directamente, pero quiero que el paquete se cargue y ejecute su inicializacion”.

En Go, un paquete puede tener “codigo de inicializacion” que se ejecuta automaticamente al arrancar el programa. Normalmente esto esta relacionado con el registro de ciertas capacidades. El ejemplo mas popular del mundo real son los drivers de bases de datos: no los llamas directamente, pero se “registran” dentro de database/sql. Otro ejemplo habitual es el registro de formatos de decodificacion (por ejemplo, conectas un paquete de formato y el decodificador general aprende a entenderlo).

En nuestro nivel es importante fijar dos cosas.

La primera: el _-import no cuenta como no utilizado. Es decir, el compilador no se queja porque has dicho explicitamente: “necesito el hecho de importar”.

La segunda: el _-import casi siempre significa un efecto secundario, y los efectos secundarios empeoran la previsibilidad. Por eso, para un principiante, conviene tratar el _-import como un cuchillo afilado: es util, pero no conviene agitarlo entre la multitud.

Ejemplo “vacio” solo por la sintaxis

Este ejemplo no hace nada util, pero muestra la mecanica: con un import normal de math el compilador protestaria, y con _ no.

package main

import (
	"fmt"
	_ "math"
)

func main() {
	fmt.Println("started") // started
}

Si, es absurdo. Pero es como un maniqui de entrenamiento: practicas en el para no tener que practicar en produccion.

6. Errores tipicos al trabajar con imports

Error n.º 1: “Importo antes, para no olvidarlo luego”.
En Go esto no funciona: el compilador no permitira mantener paquetes sin usar. Y eso incluso es bueno: no llevas un ladrillo en la mochila “por si acaso”. Si un paquete no hace falta, no se importa. Si hace falta, lo añades y lo usas de inmediato; de lo contrario, la compilacion se detendra y mostrara honestamente el problema.

Error n.º 2: alias por “estilo” y no por sentido.
A veces los principiantes convierten el codigo en un acertijo: f.Println, s.TrimSpace, st.Atoi, e.New… Formalmente el programa funciona, pero leerlo es dificil. El alias es bueno cuando resuelve un problema concreto: conflicto de nombres, mejora real de claridad, o un caso raro de shadowing del nombre del paquete. En todos los demas casos, mejor dejar el nombre estandar del paquete.

Error n.º 3: confundir _ en el import con _ en el codigo.
El simbolo _ aparece en muchos sitios, pero su significado cambia. En el import _ "pkg" significa “importar por el efecto secundario de la inicializacion”. En una asignacion x, _ := ... significa “hay resultado, pero no lo necesito”. Si mezclas estas ideas en la cabeza, puedes empezar a pensar que _ es simplemente “tirar algo innecesario”. En el caso del blank import, no lo “tiras”: lo “conectas en silencio”.

Error n.º 4: esperar que el import funcione “para todo el paquete” y no para el archivo.
Incluso si tienes varios archivos dentro de un mismo paquete, los imports se escriben en cada archivo por separado. Esto sorprende a veces: “pero si ya importé fmt en otro archivo”. Si, pero ese otro archivo no comparte imports con el actual. Asi funciona: cada archivo declara sus dependencias para poder leerse y entenderse de forma aislada.

1
Tarea
Go SELF, nivel 10, lección 3
Bloqueada
Importación limpia
Importación limpia
1
Tarea
Go SELF, nivel 10, lección 3
Bloqueada
Etiqueta de la tarea
Etiqueta de la tarea
1
Tarea
Go SELF, nivel 10, lección 3
Bloqueada
Conflicto de nombres
Conflicto de nombres
1
Tarea
Go SELF, nivel 10, lección 3
Bloqueada
Inicio y pasaporte
Inicio y pasaporte
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION