Hampir semua program Go menyentuh package fmt: menampilkan hasil, menyusun teks terformat, membaca masukan, sampai membungkus pesan error. Chapter fmt.Println telah memperkenalkan fungsi cetak dasarnya; chapter ini membedah sisanya: tabel verb lengkap, lebar dan presisi kolom, keluarga Sprint, interface Stringer, verb %w, dan fmt.Scan. Seluruh contoh dijalankan sungguhan sehingga setiap verb dapat dibandingkan dengan hasil aslinya.

Tiga Keluarga Fungsi #

Package fmt menyusun fungsinya dalam tiga keluarga. Setiap keluarga punya tiga variasi: bentuk polos, akhiran ln yang menambah spasi antar argumen lalu baris baru, dan akhiran f yang memakai pola format. Tabel berikut merangkum ketiganya:

KeluargaFungsiTujuan
CetakPrint, Println, PrintfMenulis ke standard output (layar)
StringSprint, Sprintln, SprintfMengembalikan string tanpa mencetak
TulisFprint, Fprintln, FprintfMenulis ke io.Writer mana pun, misalnya os.Stdout atau berkas

Keluarga Sprint dipakai saat teks terformat dibutuhkan sebagai nilai, misalnya isi field struct atau pesan log. Keluarga Fprint menulis ke io.Writer mana pun dan muncul lagi pada chapter io dan utilitasnya .

Tabel Verb Format #

Verb adalah penanda tempat pada pola format yang diganti nilai argumen, misalnya %d untuk bilangan bulat. Berikut verb yang paling sering dipakai beserta contoh hasilnya:

VerbKegunaanContoh hasil
%vformat default untuk tipe apa pun{Kopi Gayo 25000}
%+vseperti %v, plus nama field struct{Nama:Kopi Gayo Harga:25000}
%#vrepresentasi sintaks Gomain.Produk{Nama:"Kopi Gayo", Harga:25000}
%Ttipe dari nilaimain.Produk
%dbilangan bulat basis sepuluh255
%steks string mentahGo
%qstring dengan tanda kutip"Go"
%xheksadesimal: bilangan atau isi byte stringff, 476f
%fdesimal dengan enam angka di belakang koma3.140000
%gdesimal paling ringkas3.14
%enotasi ilmiah3.140000e+00
%tnilai booleantrue
%palamat pointer, misalnya 0xc0000123456berbeda tiap eksekusi

Program Utuh #

Berkas fmt-demo.go mempraktikkan semua materi di atas dalam satu program:

go
package main

import (
	"errors"
	"fmt"
	"os"
)

// Produk tidak memiliki method String,
// sehingga fmt memakai format bawaan untuk struct.
type Produk struct {
	Nama  string
	Harga int
}

// Siswa mengimplementasikan interface fmt.Stringer.
type Siswa struct {
	Nama string
	Umur int
}

// String membuat fmt memakai teks ini alih-alih format struct bawaan.
func (s Siswa) String() string {
	return fmt.Sprintf("siswa %s (%d tahun)", s.Nama, s.Umur)
}

func main() {
	// Keluarga Sprint menghasilkan string tanpa mencetak apa pun.
	sapaan := fmt.Sprint("Harga kopi: ", 25000)
	barisan := fmt.Sprintln("Stok kopi:", 12)
	ringkas := fmt.Sprintf("%s punya %d gram", "Budi", 250)
	fmt.Println(sapaan)
	fmt.Printf("sprintln: %q\n", barisan)
	fmt.Println(ringkas)

	// Verb untuk struct tanpa method String.
	kopi := Produk{Nama: "Kopi Gayo", Harga: 25000}
	fmt.Printf("%%v  : %v\n", kopi)
	fmt.Printf("%%+v : %+v\n", kopi)
	fmt.Printf("%%#v : %#v\n", kopi)
	fmt.Printf("%%T  : %T\n", kopi)

	// Verb untuk nilai dasar.
	fmt.Printf("%%d  : %d  %%x : %x\n", 255, 255)
	fmt.Printf("%%s  : %s  %%q : %q\n", "Go", "Go")
	fmt.Printf("%%x  : %x (string)\n", "Go")
	fmt.Printf("%%f  : %f\n", 3.14)
	fmt.Printf("%%g  : %g  %%e : %e\n", 3.14, 3.14)
	fmt.Printf("%%t  : %t\n", 255 > 100)

	// Lebar dan presisi kolom.
	fmt.Printf("[%%8.2f] : [%8.2f]\n", 1234.567)
	fmt.Printf("[%%-10s] : [%-10s]\n", "Go")
	fmt.Printf("[%%05d]  : [%05d]\n", 42)

	// Fprintf menulis ke io.Writer mana pun, bukan hanya layar.
	fmt.Fprintf(os.Stdout, "fprintf ke os.Stdout: %s\n", "berhasil")

	// Stringer dipanggil secara otomatis oleh fmt.
	siti := Siswa{Nama: "Siti", Umur: 21}
	fmt.Println(siti)
	fmt.Printf("%v dan %s\n", siti, siti)

	// Verb %w membungkus error agar tetap bisa diperiksa dengan errors.Is.
	galat := errors.New("sambungan database gagal")
	dibungkus := fmt.Errorf("ambil data: %w", galat)
	fmt.Println(dibungkus)
	fmt.Println("errors.Is:", errors.Is(dibungkus, galat))
}

Jalankan program tersebut dari folder chapter:

bash
go run fmt-demo.go

Output yang Dihasilkan:

text
Harga kopi: 25000
sprintln: "Stok kopi: 12\n"
Budi punya 250 gram
%v  : {Kopi Gayo 25000}
%+v : {Nama:Kopi Gayo Harga:25000}
%#v : main.Produk{Nama:"Kopi Gayo", Harga:25000}
%T  : main.Produk
%d  : 255  %x : ff
%s  : Go  %q : "Go"
%x  : 476f (string)
%f  : 3.140000
%g  : 3.14  %e : 3.140000e+00
%t  : true
[%8.2f] : [ 1234.57]
[%-10s] : [Go        ]
[%05d]  : [00042]
fprintf ke os.Stdout: berhasil
siswa Siti (21 tahun)
siswa Siti (21 tahun) dan siswa Siti (21 tahun)
ambil data: sambungan database gagal
errors.Is: true

Mari kita telaah baris demi baris program di atas:

  1. Baris 11-25: Produk tanpa method String memakai format struct bawaan, sedangkan Siswa mengimplementasikan fmt.Stringer sehingga fmt memakai teks kustomnya.
  2. Baris 29-34: keluarga Sprint mengembalikan string tanpa mencetak; tanda baris baru milik Sprintln terlihat saat isinya dicetak dengan %q.
  3. Baris 38-49: membandingkan verb %v, %+v, %#v, %T, lalu verb nilai dasar; %x pada string "Go" menghasilkan heksadesimal isi byte-nya, 476f.
  4. Baris 52-54: %8.2f mengatur lebar 8 dengan dua angka di belakang koma, %-10s merata kiri, dan %05d menambah nol di depan.
  5. Baris 57-62: Fprintf menulis ke io.Writer mana pun (os.Stdout), dan Println/Printf memanggil method String() milik siti secara otomatis.
  6. Baris 65-68: verb %w membungkus error asli sehingga errors.Is tetap menemukannya.

Lebar dan Presisi Kolom #

Angka di antara persen dan verb mengatur tata letak kolom. Pola %8.2f berarti lebar minimum 8 karakter dengan 2 angka di belakang koma dan perataan kanan, sehingga 1234.567 menjadi 1234.57. Tanda minus pada %-10s meratakan ke kiri, sementara %05d mengisi ruang kosong dengan nol — cukup untuk laporan rapi di terminal.

Interface fmt.Stringer #

Interface Stringer adalah kontrak paling sederhana di fmt:

go
type Stringer interface {
	String() string
}

Ketika sebuah tipe memiliki method String() string, seluruh fungsi fmt memakai hasilnya untuk verb %v dan %s. Baris 61-62 membuktikannya: Siswa dicetak sebagai siswa Siti (21 tahun), bukan {Siti 21}.

Membungkus Error dengan %w #

Verb %w khusus dipakai di fmt.Errorf untuk membungkus error:

go
dibungkus := fmt.Errorf("ambil data: %w", galat)

Membaca Input dengan fmt.Scan #

Selain mencetak, fmt membaca nilai dari standard input melalui Scan, Scanln, dan Scanf. Berkas fmt-scan-demo.go membaca satu string dan satu bilangan:

go
package main

import (
	"fmt"
	"os"
)

func main() {
	var nama string
	var umur int

	// Scan membaca nilai yang dipisahkan spasi dari standard input.
	n, err := fmt.Scan(&nama, &umur)
	if err != nil {
		fmt.Fprintln(os.Stderr, "input tidak lengkap:", err)
		os.Exit(1)
	}
	fmt.Printf("terbaca %d nilai: %s berumur %d tahun\n", n, nama, umur)
}

Program ini paling mudah diuji dengan mengirim teks lewat pipa:

bash
echo "Budi 25" | go run fmt-scan-demo.go

Output yang Dihasilkan:

text
terbaca 2 nilai: Budi berumur 25 tahun

Mari kita telaah baris demi baris program di atas:

  1. Baris 9-10 (var nama string dan var umur int): menyiapkan variabel penampung yang akan diisi Scan.
  2. Baris 13 (n, err := fmt.Scan(&nama, &umur)): membaca dua token yang dipisahkan spasi atau baris baru; operator & mengirim alamat variabel agar Scan dapat mengisinya (lihat chapter Pointer dan Memory ).
  3. Baris 14-17 (if err != nil): menjaga program saat masukan tidak lengkap; tanpa input, Scan mengembalikan error EOF dan program keluar dengan kode 1.
  4. Baris 18: mencetak jumlah token yang terbaca beserta nilainya.

Scan cocok untuk input berbasis token seperti angka yang dipisah spasi. Untuk membaca baris penuh, chapter Package bufio menyediakan Scanner yang lebih nyaman.

Referensi #

Dengan penguasaan fmt, output program Anda menjadi rapi dan galat tetap tertelusuri. Chapter berikutnya membahas package os: argumen command line, environment variable, dan kontrol keluar program.

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

fmt-demo.go

Unduh berkas
go
package main

import (
	"errors"
	"fmt"
	"os"
)

// Produk tidak memiliki method String,
// sehingga fmt memakai format bawaan untuk struct.
type Produk struct {
	Nama  string
	Harga int
}

// Siswa mengimplementasikan interface fmt.Stringer.
type Siswa struct {
	Nama string
	Umur int
}

// String membuat fmt memakai teks ini alih-alih format struct bawaan.
func (s Siswa) String() string {
	return fmt.Sprintf("siswa %s (%d tahun)", s.Nama, s.Umur)
}

func main() {
	// Keluarga Sprint menghasilkan string tanpa mencetak apa pun.
	sapaan := fmt.Sprint("Harga kopi: ", 25000)
	barisan := fmt.Sprintln("Stok kopi:", 12)
	ringkas := fmt.Sprintf("%s punya %d gram", "Budi", 250)
	fmt.Println(sapaan)
	fmt.Printf("sprintln: %q\n", barisan)
	fmt.Println(ringkas)

	// Verb untuk struct tanpa method String.
	kopi := Produk{Nama: "Kopi Gayo", Harga: 25000}
	fmt.Printf("%%v  : %v\n", kopi)
	fmt.Printf("%%+v : %+v\n", kopi)
	fmt.Printf("%%#v : %#v\n", kopi)
	fmt.Printf("%%T  : %T\n", kopi)

	// Verb untuk nilai dasar.
	fmt.Printf("%%d  : %d  %%x : %x\n", 255, 255)
	fmt.Printf("%%s  : %s  %%q : %q\n", "Go", "Go")
	fmt.Printf("%%x  : %x (string)\n", "Go")
	fmt.Printf("%%f  : %f\n", 3.14)
	fmt.Printf("%%g  : %g  %%e : %e\n", 3.14, 3.14)
	fmt.Printf("%%t  : %t\n", 255 > 100)

	// Lebar dan presisi kolom.
	fmt.Printf("[%%8.2f] : [%8.2f]\n", 1234.567)
	fmt.Printf("[%%-10s] : [%-10s]\n", "Go")
	fmt.Printf("[%%05d]  : [%05d]\n", 42)

	// Fprintf menulis ke io.Writer mana pun, bukan hanya layar.
	fmt.Fprintf(os.Stdout, "fprintf ke os.Stdout: %s\n", "berhasil")

	// Stringer dipanggil secara otomatis oleh fmt.
	siti := Siswa{Nama: "Siti", Umur: 21}
	fmt.Println(siti)
	fmt.Printf("%v dan %s\n", siti, siti)

	// Verb %w membungkus error agar tetap bisa diperiksa dengan errors.Is.
	galat := errors.New("sambungan database gagal")
	dibungkus := fmt.Errorf("ambil data: %w", galat)
	fmt.Println(dibungkus)
	fmt.Println("errors.Is:", errors.Is(dibungkus, galat))
}

fmt-scan-demo.go

Unduh berkas
go
package main

import (
	"fmt"
	"os"
)

func main() {
	var nama string
	var umur int

	// Scan membaca nilai yang dipisahkan spasi dari standard input.
	n, err := fmt.Scan(&nama, &umur)
	if err != nil {
		fmt.Fprintln(os.Stderr, "input tidak lengkap:", err)
		os.Exit(1)
	}
	fmt.Printf("terbaca %d nilai: %s berumur %d tahun\n", n, nama, umur)
}