Menu

Printf e Sprintf in Golang: guida ai verbi di formato di fmt

Come il package fmt di Go stampa e formatta i valori: Println, Printf, Sprintf ed Errorf a confronto, la tabella completa dei verbi di formato (%v, %+v, %d, %s, %q, %f, %T, %w e altri), larghezza, precisione e riempimento.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Il package fmt ha tre famiglie di funzioni di stampa, e ogni famiglia ha le stesse tre varianti:

FunzioneDove va l'outputFormato
Print, Println, Printfstandard outputpredefinito, predefinito con spazi e a capo, stringa di formato
Sprint, Sprintln, Sprintfuna string restituitagli stessi tre stili
Fprint, Fprintln, Fprintfqualsiasi io.Writer (file, buffer, risposta HTTP)gli stessi tre stili
Errorfun error restituitostringa di formato, più %w per il wrapping

Println aggiunge spazi tra gli operandi e un a capo alla fine. Printf non aggiunge nulla: il \n lo scrivi tu. Print aggiunge spazi solo tra operandi che non sono entrambi stringhe, un comportamento abbastanza sorprendente da spingere la maggior parte del codice a usare Println o Printf.

Verbi di formato

Generali

VerboStampaEsempio di output
%vil valore in un formato predefinito{Ana 31 [admin]}
%+vle struct con i nomi dei campi{Name:Ana Age:31 Tags:[admin]}
%#vla sintassi Go del valoremain.User{Name:"Ana", Age:31, Tags:[]string{"admin"}}
%Til tipomain.User
%%un simbolo di percentuale letterale%

%+v è quello da usare durante il debug. Un puntatore a una struct viene stampato come &{...} invece che come indirizzo. Le mappe vengono stampate con le chiavi ordinate, quindi l'output è stabile anche se l'ordine di iterazione delle mappe è casuale.

Interi

VerboSignificatofmt.Sprintf(verb, 255)
%ddecimale255
%bbinario11111111
%oottale377
%Oottale con prefisso 0o0o377
%x / %Xesadecimale, minuscolo o maiuscoloff / FF
%#xesadecimale con prefisso 0x0xff
%cil carattere con quel code pointÿ
%qun letterale di carattere tra apici'ÿ'
%Uformato UnicodeU+00FF

Float

VerboSignificatofmt.Sprintf(verb, 1234.5678)
%fdecimale, 6 cifre dopo la virgola per impostazione predefinita1234.567800
%.2fdecimale, 2 cifre dopo la virgola1234.57
%enotazione scientifica1.234568e+03
%g%e o %f, quello più corto, senza zeri finali1234.5678
%vcome %g1234.5678

%.2f arrotonda il valore binario esatto del float, quindi fmt.Sprintf("%.2f", 2.675) dà 2.67: il float64 più vicino a 2,675 è leggermente inferiore. Non formattare mai importi di denaro a partire da un float; tieni i centesimi in un intero.

Stringhe e byte

VerboSignificatofmt.Sprintf(verb, "go\n")
%sla stringa così com'ègo e un a capo
%qtra virgolette doppie, con le sequenze di escape visibili"go\n"
%xesadecimale di ogni byte676f0a
% xesadecimale con spazi67 6f 0a

%s su un []byte lo stampa come testo; %v stampa i numeri ([104 105]).

Altri tipi

VerboTipoStampa
%tbooltrue o false
%ppuntatore, slice, map, channel, funcl'indirizzo, come 0xc000012345
%werror (solo in Errorf)il messaggio dell'errore, e lo avvolge

Larghezza, precisione e riempimento

Tra % e il verbo puoi mettere flag, una larghezza e una precisione:

FormaEffetto
%5dlarghezza 5, allineato a destra (riempie a sinistra con spazi)
%-5dlarghezza 5, allineato a sinistra
%05driempie con zeri
%.2f2 cifre dopo la virgola
%8.2flarghezza 8 e 2 decimali
%.3sal massimo 3 caratteri della stringa
%+dmostra sempre il segno
%*dlarghezza presa dall'argomento successivo

Nota che %.0f di 2.5 stampa 2: qui Go arrotonda la metà al numero pari. Per le stringhe la larghezza conta le rune, non le colonne visualizzate, quindi i caratteri CJK e le emoji possono comunque disallineare una tabella. Per colonne allineate di testo variabile, text/tabwriter fa le misure al posto tuo.

Indici degli argomenti

%[n] sceglie un argomento in base alla posizione, il che ti permette di riusarlo:

fmt.Printf("%[2]s %[1]s\n", "world", "hello") // hello world
fmt.Printf("%d %[1]x %[1]b\n", 10)             // 10 a 1010

Errorf e %w

fmt.Errorf costruisce un error a partire da una stringa di formato. Con %w avvolge anche un altro errore, così i chiamanti possono ancora riconoscere l'originale:

Usa %w quando i chiamanti potrebbero dover controllare la causa, e %v quando vuoi nasconderla di proposito. Da Go 1.20 una chiamata a Errorf può contenere più verbi %w. La pagina sulla gestione degli errori approfondisce il wrapping.

Formattazione personalizzata con String()

Qualsiasi tipo con un metodo String() string controlla come lo mostrano %v, %s e Println:

%d scavalca String() e stampa il numero sottostante. Per i tipi di errore il metodo equivalente è Error() string, che ha la precedenza su String().

Quando il verbo è sbagliato

fmt non va mai in panic per un formato errato. Stampa il problema direttamente nel testo:

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)

Questo output tende ad arrivare in produzione perché non fa crashare nulla. go vet li rileva tutti e tre durante la build:

./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

Note sulle prestazioni

fmt riceve ogni argomento come any ed esamina il suo tipo durante l'esecuzione (ricorrendo alla reflection per struct, slice e mappe), il che va bene per i log e l'output ma si nota nei cicli stretti. Per convertire un singolo numero, strconv.Itoa e strconv.FormatFloat sono più veloci di Sprintf. Per costruire una stringa lunga in un ciclo, scrivi in uno strings.Builder con fmt.Fprintf(&b, ...) invece di concatenare i risultati di Sprintf.

Domande frequenti

Qual è la differenza tra Println, Printf e Sprintf in Go?

fmt.Println stampa i suoi argomenti separati da spazi con un a capo alla fine. fmt.Printf stampa seguendo una stringa di formato e non aggiunge l'a capo. fmt.Sprintf formatta come Printf ma restituisce il risultato come stringa invece di stamparlo. fmt.Errorf fa lo stesso e restituisce un error.

Come stampo una struct con i nomi dei campi in Go?

Usa %+v: fmt.Printf("%+v\n", user) stampa {Name:Ana Age:31}. %v stampa solo i valori, {Ana 31}, e %#v stampa la sintassi Go compreso il tipo, main.User{Name:"Ana", Age:31}.

Come formatto un float con 2 decimali in Go?

Usa %.2f: fmt.Sprintf("%.2f", 3.14159) restituisce "3.14". Aggiungi una larghezza per allineare le colonne, %8.2f, o un segno meno per allineare a sinistra, %-8.2f. strconv.FormatFloat(f, 'f', 2, 64) dà lo stesso risultato senza una stringa di formato.

Cosa fa %w in fmt.Errorf?

%w formatta un errore come %v e in più lo avvolge, così il nuovo errore porta con sé l'originale. errors.Is ed errors.As possono quindi trovare l'errore avvolto: err := fmt.Errorf("load config: %w", os.ErrNotExist) rende vero errors.Is(err, os.ErrNotExist). %w funziona solo in fmt.Errorf.

Perché il mio output mostra %!d(string=...)?

Il verbo non corrisponde al tipo dell'argomento, per esempio %d con una stringa. fmt stampa il problema nel testo invece di andare in panic: %!d(string=oops). Gli argomenti mancanti stampano %!d(MISSING) e quelli in più %!(EXTRA int=2). go vet li rileva tutti e tre prima che tu esegua il programma.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA