Menu

Printf y Sprintf en Golang: chuleta de verbos de formato de fmt

Cómo imprime y formatea valores el paquete fmt de Go: Println frente a Printf, Sprintf y Errorf, la tabla completa de verbos de formato (%v, %+v, %d, %s, %q, %f, %T, %w y más), ancho, precisión y relleno.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

El paquete fmt tiene tres familias de funciones de impresión, y cada familia tiene las mismas tres variantes:

FunciónLa salida va aFormato
Print, Println, Printfla salida estándarpor defecto, por defecto con espacios y salto de línea, cadena de formato
Sprint, Sprintln, Sprintfun string devueltolos mismos tres estilos
Fprint, Fprintln, Fprintfcualquier io.Writer (archivo, buffer, respuesta HTTP)los mismos tres estilos
Errorfun error devueltocadena 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

VerboImprimeEjemplo de salida
%vel valor en un formato por defecto{Ana 31 [admin]}
%+vstructs con los nombres de los campos{Name:Ana Age:31 Tags:[admin]}
%#vsintaxis Go del valormain.User{Name:"Ana", Age:31, Tags:[]string{"admin"}}
%Tel tipomain.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

VerboSignificadofmt.Sprintf(verb, 255)
%ddecimal255
%bbinario11111111
%ooctal377
%Ooctal con prefijo 0o0o377
%x / %Xhexadecimal, en minúsculas o mayúsculasff / FF
%#xhexadecimal con prefijo 0x0xff
%cel carácter con ese code pointÿ
%qun literal de carácter entre comillas'ÿ'
%Uformato UnicodeU+00FF

Flotantes

VerboSignificadofmt.Sprintf(verb, 1234.5678)
%fdecimal, 6 decimales por defecto1234.567800
%.2fdecimal, 2 decimales1234.57
%enotación científica1.234568e+03
%g%e o %f, el más corto, sin ceros finales1234.5678
%vigual que %g1234.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

VerboSignificadofmt.Sprintf(verb, "go\n")
%sel string tal cualgo y un salto de línea
%qentre comillas dobles, con los escapes visibles"go\n"
%xhexadecimal de cada byte676f0a
% xhexadecimal con espacios67 6f 0a

%s sobre un []byte lo imprime como texto; %v imprime los números ([104 105]).

Otros tipos

VerboTipoImprime
%tbooltrue o false
%ppuntero, slice, map, channel, funcla dirección, como 0xc000012345
%werror (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:

FormaEfecto
%5dancho 5, alineado a la derecha (relleno con espacios a la izquierda)
%-5dancho 5, alineado a la izquierda
%05drelleno con ceros
%.2f2 dígitos tras el punto decimal
%8.2fancho 8 y 2 decimales
%.3scomo mucho 3 caracteres del string
%+dmostrar siempre el signo
%*dancho 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.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR