Paquete fmt en Go: Guía Completa con Ejemplos Avanzados
El paquete fmt es fundamental para operaciones de entrada/salida en Go. Esta guía cubre todas sus funciones con ejemplos realistas y técnicas avanzadas.
Funciones Básicas de Impresión
1. Print y Println
Diferencias Clave:
Printno añade espacios automáticos entre argumentosPrintlnañade espacios y un salto de línea final
Ejemplo Mejorado:
func main() {
// Comportamiento con múltiples argumentos
fmt.Print("Hoy es:", time.Now().Weekday(), "\n") // Hoy es:Monday
fmt.Println("Hoy es:", time.Now().Weekday()) // Hoy es: Monday\n
// Impresión de estructuras
user := struct {
Name string
Age int
}{"Alice", 30}
fmt.Println("Usuario:", user) // Usuario: {Alice 30}
}
2. Printf - Formateo Avanzado
Verbos Comunes:
%sCadena%dEntero%fFlotante (%.2fpara 2 decimales)%tBooleano%vValor en formato predeterminado%+vCampos de estructura con nombres%#vSintaxis Go del valor
Ejemplo Completo:
func main() {
type Product struct {
ID int
Name string
Price float64
InStock bool
}
p := Product{102, "Go Programming Book", 39.99, true}
fmt.Printf("Detalle básico: %v\n", p)
// Detalle básico: {102 Go Programming Book 39.99 true}
fmt.Printf("Detalle extendido: %+v\n", p)
// Detalle extendido: {ID:102 Name:Go Programming Book Price:39.99 InStock:true}
fmt.Printf("Precio formateado: $%.2f\n", p.Price)
// Precio formateado: $39.99
}
Funciones de Cadena (Sprint Family)
3. Sprintf - Construcción de Mensajes
Caso de Uso: Generar HTML dinámico o mensajes de log estructurados
func generateEmailTemplate(userName string, expiration time.Time) string {
return fmt.Sprintf(`
<html>
<body>
<h1>Hola, %s!</h1>
<p>Tu suscripción expira en %d días</p>
</body>
</html>
`, userName, int(expiration.Sub(time.Now()).Hours()/24))
}
4. Sprintln vs Sprint
Ejemplo Comparativo:
func main() {
logEntry := fmt.Sprint("Error en ", time.Now().Format("2006-01-02"), "\n")
// "Error en 2023-10-25\n"
logEntryLn := fmt.Sprintln("Error en", time.Now().Format("2006-01-02"))
// "Error en 2023-10-25\n"
}
Entrada/Salida con Interfaces (Fprint Family)
5. Fprintf - Escritura en Archivos
Ejemplo Práctico:
func writeConfig(filePath string, config map[string]any) error {
file, err := os.Create(filePath)
if err != nil {
return fmt.Errorf("error creando archivo: %w", err)
}
defer file.Close()
for key, value := range config {
_, err := fmt.Fprintf(file, "%s = %v\n", key, value)
if err != nil {
return err
}
}
return nil
}
6. Fscan - Lectura desde io.Reader
Ejemplo Avanzado:
func parseServerConfig(r io.Reader) (host string, port int, err error) {
_, err = fmt.Fscanf(r, "host:%s port:%d", &host, &port)
if err != nil {
return "", 0, fmt.Errorf("formato de configuración inválido: %w", err)
}
return host, port, nil
}
// Uso:
config := strings.NewReader("host:localhost port:8080")
host, port, err := parseServerConfig(config)
Manejo de Errores
7. Errorf con Wrapping
Mejor Práctica: Usar %w para envolver errores
func loadUserData(userID int) ([]byte, error) {
data, err := os.ReadFile(fmt.Sprintf("users/%d.json", userID))
if err != nil {
return nil, fmt.Errorf("error cargando usuario %d: %w", userID, err)
}
return data, nil
}
Funciones de Escaneo
8. Scan vs Scanln - Captura de Entrada
Diferencias Clave:
Scanlee hasta cualquier espacio en blancoScanlnlee hasta nueva línea
Ejemplo con Validación:
func getCredentials() (username, password string) {
fmt.Print("Ingrese usuario: ")
_, err := fmt.Scanln(&username)
if err != nil {
log.Fatal("Error leyendo usuario:", err)
}
fmt.Print("Ingrese contraseña: ")
_, err = fmt.Scanln(&password)
if err != nil {
log.Fatal("Error leyendo contraseña:", err)
}
return username, password
}
9. Sscanf - Parseo de Cadenas
Caso de Uso: Procesar registros de log
func parseLogEntry(entry string) (time.Time, string, error) {
var (
timestamp string
level string
message string
)
_, err := fmt.Sscanf(entry, "[%s] %s: %s", ×tamp, &level, &message)
if err != nil {
return time.Time{}, "", err
}
parsedTime, err := time.Parse("2006-01-02T15:04:05Z07:00", timestamp)
return parsedTime, message, err
}
Verbos Especiales y Trucos
10. Formateo Avanzado
func main() {
// Base numérica
fmt.Printf("Hex: %x, Bin: %b, Octal: %o\n", 255, 255, 255)
// Relleno y alineación
fmt.Printf("|%10s|%-10s|\n", "derecha", "izquierda")
// Caracteres Unicode
fmt.Printf("Corazón: %c\n", '\u2764')
// Punteros
x := 42
fmt.Printf("Dirección: %p\n", &x)
}
Mejores Prácticas
- Validación de Entrada:
var age int n, err := fmt.Scanf("%d", &age) if err != nil || n != 1 { // Manejar error } - Optimización de Rendimiento:
- Usar
fmt.Fprinten lugar de concatenar strings para output directo - Pre-allocatar buffers con
strings.Builderpara múltiples operaciones
- Usar
- Logging Profesional:
func logTransaction(t Transaction) { fmt.Printf("[%s] %-15s $%7.2f\n", time.Now().Format("2006-01-02 15:04:05"), t.Type, t.Amount) } - Manejo Seguro de Errores:
if _, err := fmt.Fprintf(writer, data); err != nil { // Manejar error de escritura }
Comparativa de Funciones
| Función | Salida | Formato | Destino | Retorno |
|---|---|---|---|---|
Print |
Stdout | No | - | Bytes |
Println |
Stdout | No | - | Bytes |
Printf |
Stdout | Sí | - | Bytes |
Sprint |
- | No | String | String |
Fprintf |
Custom | Sí | io.Writer | Bytes |
Errorf |
- | Sí | error | error |
Este contenido ampliado provee ejemplos prácticos, cubre casos de uso avanzados, y ofrece recomendaciones profesionales para usar efectivamente el paquete fmt en aplicaciones reales.