El paquete fmt tiene tres familias de funciones de impresión, y cada familia tiene las mismas tres variantes:
| Función | La salida va a | Formato |
|---|---|---|
Print, Println, Printf | la salida estándar | por defecto, por defecto con espacios y salto de línea, cadena de formato |
Sprint, Sprintln, Sprintf | un string devuelto | los mismos tres estilos |
Fprint, Fprintln, Fprintf | cualquier io.Writer (archivo, buffer, respuesta HTTP) | los mismos tres estilos |
Errorf | un error devuelto | cadena de formato, más %w para envolver |
Println añade espacios entre operandos y un salto de línea al final. Printf no añade nada: el \n lo escribes tú. Print añade espacios solo entre operandos que no son strings, lo cual sorprende lo suficiente como para que la mayor parte del código use Println o Printf.
Verbos de formato
Generales
| Verbo | Imprime | Ejemplo de salida |
|---|---|---|
%v | el valor en un formato por defecto | {Ana 31 [admin]} |
%+v | structs con los nombres de los campos | {Name:Ana Age:31 Tags:[admin]} |
%#v | sintaxis Go del valor | main.User{Name:"Ana", Age:31, Tags:[]string{"admin"}} |
%T | el tipo | main.User |
%% | un signo de porcentaje literal | % |
%+v es el que conviene usar al depurar. Un puntero a un struct se imprime como &{...} en lugar de como una dirección. Los maps se imprimen con las claves ordenadas, así que la salida es estable aunque el orden de iteración de un map sea aleatorio.
Enteros
| Verbo | Significado | fmt.Sprintf(verb, 255) |
|---|---|---|
%d | decimal | 255 |
%b | binario | 11111111 |
%o | octal | 377 |
%O | octal con prefijo 0o | 0o377 |
%x / %X | hexadecimal, en minúsculas o mayúsculas | ff / FF |
%#x | hexadecimal con prefijo 0x | 0xff |
%c | el carácter con ese code point | ÿ |
%q | un literal de carácter entre comillas | 'ÿ' |
%U | formato Unicode | U+00FF |
Flotantes
| Verbo | Significado | fmt.Sprintf(verb, 1234.5678) |
|---|---|---|
%f | decimal, 6 decimales por defecto | 1234.567800 |
%.2f | decimal, 2 decimales | 1234.57 |
%e | notación científica | 1.234568e+03 |
%g | %e o %f, el más corto, sin ceros finales | 1234.5678 |
%v | igual que %g | 1234.5678 |
%.2f redondea el valor binario exacto del float, así que fmt.Sprintf("%.2f", 2.675) da 2.67: el float64 más cercano a 2.675 está un poco por debajo. Nunca formatees dinero a partir de un float; guarda los céntimos en un entero.
Strings y bytes
| Verbo | Significado | fmt.Sprintf(verb, "go\n") |
|---|---|---|
%s | el string tal cual | go y un salto de línea |
%q | entre comillas dobles, con los escapes visibles | "go\n" |
%x | hexadecimal de cada byte | 676f0a |
% x | hexadecimal con espacios | 67 6f 0a |
%s sobre un []byte lo imprime como texto; %v imprime los números ([104 105]).
Otros tipos
| Verbo | Tipo | Imprime |
|---|---|---|
%t | bool | true o false |
%p | puntero, slice, map, channel, func | la dirección, como 0xc000012345 |
%w | error (solo en Errorf) | el mensaje del error, y lo envuelve |
Ancho, precisión y relleno
Entre % y el verbo puedes poner flags, un ancho y una precisión:
| Forma | Efecto |
|---|---|
%5d | ancho 5, alineado a la derecha (relleno con espacios a la izquierda) |
%-5d | ancho 5, alineado a la izquierda |
%05d | relleno con ceros |
%.2f | 2 dígitos tras el punto decimal |
%8.2f | ancho 8 y 2 decimales |
%.3s | como mucho 3 caracteres del string |
%+d | mostrar siempre el signo |
%*d | ancho tomado del siguiente argumento |
Ojo: %.0f de 2.5 imprime 2, porque aquí Go redondea al par más cercano. En los strings, el ancho cuenta runes, no columnas en pantalla, así que los caracteres CJK y los emoji todavía pueden desalinear una tabla. Para columnas alineadas de texto variable, text/tabwriter hace la medición por ti.
Índices de argumentos
%[n] elige un argumento por posición, lo que te permite reutilizarlo:
fmt.Printf("%[2]s %[1]s\n", "world", "hello") // hello world
fmt.Printf("%d %[1]x %[1]b\n", 10) // 10 a 1010
Errorf y %w
fmt.Errorf construye un error a partir de una cadena de formato. Con %w además envuelve otro error, para que quien llama pueda seguir detectando el original:
Usa %w cuando quien llama pueda necesitar comprobar la causa, y %v cuando quieras ocultarla a propósito. Desde Go 1.20 una llamada a Errorf puede contener varios verbos %w. La página de manejo de errores trata el envoltorio de errores a fondo.
Formato propio con String()
Cualquier tipo con un método String() string controla cómo lo muestran %v, %s y Println:
%d se salta String() e imprime el número subyacente. Para los tipos de error el método equivalente es Error() string, que tiene prioridad sobre String().
Cuando el verbo es incorrecto
fmt nunca provoca un panic por un formato incorrecto. Imprime el problema en la propia salida:
fmt.Printf("%d\n", "oops")
fmt.Printf("%d %d\n", 1)
fmt.Printf("%d\n", 1, 2)
%!d(string=oops)
1 %!d(MISSING)
1
%!(EXTRA int=2)
Esa salida suele llegar a producción porque no hace caer nada. go vet detecta los tres casos al compilar:
./main.go:8:2: fmt.Printf format %d has arg "oops" of wrong type string
./main.go:9:2: fmt.Printf format %d reads arg #2, but call has 1 arg
./main.go:10:2: fmt.Printf call needs 1 arg but has 2 args
Notas de rendimiento
fmt recibe cada argumento como any e inspecciona su tipo en tiempo de ejecución (recurriendo a reflexión para structs, slices y maps), lo cual está bien para logs y salida, pero se nota en bucles ajustados. Para convertir un solo número, strconv.Itoa y strconv.FormatFloat son más rápidos que Sprintf. Para construir un string largo en un bucle, escribe en un strings.Builder con fmt.Fprintf(&b, ...) en lugar de concatenar resultados de Sprintf.
Preguntas frecuentes
¿Qué diferencia hay entre Println, Printf y Sprintf en Go?
fmt.Println imprime sus argumentos separados por espacios con un salto de línea al final. fmt.Printf imprime según una cadena de formato y no añade salto de línea. fmt.Sprintf formatea igual que Printf pero devuelve el resultado como string en lugar de imprimirlo. fmt.Errorf hace lo mismo y devuelve un error.
¿Cómo imprimo un struct con los nombres de sus campos en Go?
Usa %+v: fmt.Printf("%+v\n", user) imprime {Name:Ana Age:31}. %v imprime solo los valores, {Ana 31}, y %#v imprime sintaxis de Go incluido el tipo, main.User{Name:"Ana", Age:31}.
¿Cómo formateo un float con 2 decimales en Go?
Usa %.2f: fmt.Sprintf("%.2f", 3.14159) devuelve "3.14". Añade un ancho para alinear columnas, %8.2f, o un signo menos para alinear a la izquierda, %-8.2f. strconv.FormatFloat(f, 'f', 2, 64) da el mismo resultado sin cadena de formato.
¿Qué hace %w en fmt.Errorf?
%w formatea un error como %v y además lo envuelve, así que el nuevo error lleva dentro el original. errors.Is y errors.As pueden entonces encontrar el error envuelto: err := fmt.Errorf("load config: %w", os.ErrNotExist) hace que errors.Is(err, os.ErrNotExist) sea true. %w solo funciona en fmt.Errorf.
¿Por qué mi salida muestra %!d(string=...)?
El verbo no coincide con el tipo del argumento, por ejemplo %d con un string. fmt imprime el problema en la propia salida en lugar de provocar un panic: %!d(string=oops). Los argumentos que faltan imprimen %!d(MISSING) y los que sobran %!(EXTRA int=2). go vet detecta los tres antes de ejecutar el programa.