fmt paketinde üç yazdırma fonksiyonu ailesi vardır ve her ailenin aynı üç çeşidi bulunur:
| Fonksiyon | Çıktı nereye gider | Biçim |
|---|---|---|
Print, Println, Printf | standart çıktı | varsayılan, boşluk ve yeni satırlı varsayılan, format string'i |
Sprint, Sprintln, Sprintf | döndürülen bir string | aynı üç stil |
Fprint, Fprintln, Fprintf | herhangi bir io.Writer (dosya, buffer, HTTP yanıtı) | aynı üç stil |
Errorf | döndürülen bir error | format string'i, ayrıca sarmalamak için %w |
Println işlenenler arasına boşluk, sonuna da yeni satır ekler. Printf hiçbir şey eklemez: \n'i kendiniz yazarsınız. Print yalnızca ikisi de string olmayan işlenenlerin arasına boşluk ekler; bu o kadar şaşırtıcıdır ki çoğu kod Println ya da Printf kullanır.
Format Verb'leri
Genel
| Verb | Yazdırdığı | Örnek çıktı |
|---|---|---|
%v | varsayılan biçimde değer | {Ana 31 [admin]} |
%+v | alan adlarıyla struct'lar | {Name:Ana Age:31 Tags:[admin]} |
%#v | değerin Go söz dizimi | main.User{Name:"Ana", Age:31, Tags:[]string{"admin"}} |
%T | tip | main.User |
%% | düz bir yüzde işareti | % |
Hata ayıklarken başvurulacak verb %+v'dir. Bir struct'a işaret eden pointer bir adres yerine &{...} olarak yazdırılır. Map'ler anahtarları sıralanmış olarak yazdırılır, bu yüzden map dolaşma sırası rastgele olsa da çıktı kararlıdır.
Tam sayılar
| Verb | Anlamı | fmt.Sprintf(verb, 255) |
|---|---|---|
%d | onluk | 255 |
%b | ikilik | 11111111 |
%o | sekizlik | 377 |
%O | 0o önekli sekizlik | 0o377 |
%x / %X | onaltılık, küçük ya da büyük harf | ff / FF |
%#x | 0x önekli onaltılık | 0xff |
%c | o kod noktasına sahip karakter | ÿ |
%q | tırnaklı bir karakter literal'i | 'ÿ' |
%U | Unicode biçimi | U+00FF |
Float'lar
| Verb | Anlamı | fmt.Sprintf(verb, 1234.5678) |
|---|---|---|
%f | ondalık, varsayılan 6 basamak | 1234.567800 |
%.2f | ondalık, 2 basamak | 1234.57 |
%e | bilimsel gösterim | 1.234568e+03 |
%g | %e ya da %f, hangisi kısaysa, sondaki sıfırlar olmadan | 1234.5678 |
%v | %g ile aynı | 1234.5678 |
%.2f, float'ın kesin ikili değerini yuvarlar, bu yüzden fmt.Sprintf("%.2f", 2.675) sonucu 2.67'dir: 2.675'e en yakın float64 ondan biraz küçüktür. Parayı asla bir float'tan biçimlendirmeyin; kuruşları bir tam sayıda tutun.
String'ler ve byte'lar
| Verb | Anlamı | fmt.Sprintf(verb, "go\n") |
|---|---|---|
%s | düz string | go ve bir yeni satır |
%q | çift tırnaklı, kaçış dizileri görünür | "go\n" |
%x | her baytın onaltılık değeri | 676f0a |
% x | boşluklu onaltılık | 67 6f 0a |
Bir []byte üzerinde %s onu metin olarak yazdırır; %v ise sayıları yazdırır ([104 105]).
Diğer tipler
| Verb | Tip | Yazdırdığı |
|---|---|---|
%t | bool | true ya da false |
%p | pointer, slice, map, channel, func | 0xc000012345 gibi adres |
%w | error (yalnızca Errorf içinde) | hatanın mesajı, ve onu sarmalar |
Genişlik, Hassasiyet ve Dolgu
% ile verb arasına bayraklar, bir genişlik ve bir hassasiyet koyabilirsiniz:
| Biçim | Etkisi |
|---|---|
%5d | genişlik 5, sağa hizalı (solu boşlukla doldurulur) |
%-5d | genişlik 5, sola hizalı |
%05d | sıfırlarla doldur |
%.2f | ondalık noktadan sonra 2 basamak |
%8.2f | genişlik 8 ve 2 ondalık |
%.3s | string'in en fazla 3 karakteri |
%+d | işareti her zaman göster |
%*d | genişlik sonraki argümandan alınır |
2.5 için %.0f'nin 2 yazdırdığına dikkat edin: Go burada yarımları çift sayıya yuvarlar. Genişlik, string'ler için ekran sütunlarını değil rune'ları sayar, bu yüzden CJK karakterleri ve emoji bir tabloyu yine de kaydırabilir. Değişken metinli hizalı sütunlar için ölçümü text/tabwriter sizin yerinize yapar.
Argüman indeksleri
%[n] bir argümanı konumuna göre seçer, bu da bir argümanı yeniden kullanmanızı sağlar:
fmt.Printf("%[2]s %[1]s\n", "world", "hello") // hello world
fmt.Printf("%d %[1]x %[1]b\n", 10) // 10 a 1010
Errorf ve %w
fmt.Errorf bir format string'inden bir error oluşturur. %w ile ayrıca başka bir hatayı sarmalar, böylece çağıranlar orijinali hâlâ tespit edebilir:
Çağıranların nedeni kontrol etmesi gerekebilecekse %w, nedeni bilerek gizliyorsanız %v kullanın. Go 1.20'den beri tek bir Errorf çağrısı birden fazla %w verb'ü içerebilir. Hata yönetimi sayfası sarmalamayı derinlemesine anlatıyor.
String() ile Özel Biçimlendirme
String() string metodu olan her tip, %v, %s ve Println'in onu nasıl göstereceğini kontrol eder:
%d, String()'i atlar ve temeldeki sayıyı yazdırır. Hata tipleri için eşdeğer metot Error() string'dir ve String()'den önceliklidir.
Verb Yanlış Olduğunda
fmt hatalı bir biçimde asla panic yapmaz. Sorunu satır içinde yazdırır:
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)
Bu çıktı hiçbir şeyi çökertmediği için production'a kadar ulaşma eğilimindedir. go vet üçünü de derleme zamanında yakalar:
./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
Performans Notları
fmt her argümanı bir any olarak alır ve tipini çalışma zamanında inceler (struct'lar, slice'lar ve map'ler için reflection'a başvurur); bu, loglama ve çıktı için sorun değildir ama sıkı döngülerde ölçülebilir bir maliyettir. Tek bir sayıyı dönüştürmek için strconv.Itoa ve strconv.FormatFloat, Sprintf'ten daha hızlıdır. Bir döngüde uzun bir string oluşturmak için Sprintf sonuçlarını birleştirmek yerine fmt.Fprintf(&b, ...) ile bir strings.Builder'a yazın.
Sıkça Sorulan Sorular
Go'da Println, Printf ve Sprintf arasındaki fark nedir?
fmt.Println argümanlarını boşluklarla ayırarak ve sonuna yeni satır ekleyerek yazdırır. fmt.Printf bir format string'ine göre yazdırır ve yeni satır eklemez. fmt.Sprintf, Printf ile aynı şekilde biçimlendirir ama sonucu yazdırmak yerine string olarak döndürür. fmt.Errorf de aynısını yapar ve bir error döndürür.
Go'da bir struct alan adlarıyla nasıl yazdırılır?
%+v kullanın: fmt.Printf("%+v\n", user), {Name:Ana Age:31} yazdırır. %v yalnızca değerleri yazdırır, {Ana 31}; %#v ise tip dahil Go söz dizimini yazdırır, main.User{Name:"Ana", Age:31}.
Go'da bir float 2 ondalık basamakla nasıl biçimlendirilir?
%.2f kullanın: fmt.Sprintf("%.2f", 3.14159), "3.14" döndürür. Sütunları hizalamak için bir genişlik ekleyin, %8.2f; sola hizalamak için bir eksi işareti, %-8.2f. strconv.FormatFloat(f, 'f', 2, 64) format string'i olmadan aynı sonucu verir.
fmt.Errorf içinde %w ne yapar?
%w bir hatayı %v gibi biçimlendirir ve ayrıca onu sarmalar, böylece yeni hata orijinalini taşır. errors.Is ve errors.As sonra sarmalanmış hatayı bulabilir: err := fmt.Errorf("load config: %w", os.ErrNotExist) ifadesi errors.Is(err, os.ErrNotExist) sonucunu true yapar. %w yalnızca fmt.Errorf içinde çalışır.
Çıktım neden %!d(string=...) gösteriyor?
Verb, argümanın tipiyle eşleşmiyor; örneğin %d'ye bir string verilmiş. fmt panic yerine sorunu satır içinde yazdırır: %!d(string=oops). Eksik argümanlar %!d(MISSING), fazla olanlar %!(EXTRA int=2) olarak yazdırılır. go vet üçünü de programı çalıştırmadan önce yakalar.