Setelah tahu bahwa error hanyalah nilai dengan method Error() string, pertanyaan berikutnya adalah bagaimana cara membuat nilai tersebut tanpa harus mendefinisikan struct setiap kali. Package errors dan fmt menyediakan dua konstruktor standar: errors.New untuk pesan yang selalu sama, dan fmt.Errorf untuk pesan yang dirangkai dari data runtime. Pada chapter ini kita akan memakai keduanya, memilih konstruktornya sesuai konteks, lalu mengikuti konvensi penulisan pesan error yang dipakai seluruh ekosistem Go.

Membuat Error Statis dengan errors.New #

Fungsi errors.New menerima satu string dan mengembalikan nilai error dengan pesan tersebut:

go
var ErrKoneksiTertutup = errors.New("koneksi sudah tertutup")

Pesan error seperti di atas bersifat statis: teksnya tidak berubah dari satu pemanggilan ke pemanggilan lain. Konstruktor ini cocok untuk error acuan (sentinel) yang dideklarasikan sekali di level package dan dibandingkan pemanggil dengan errors.Is. Mendeklarasikan variabel tersebut di level var juga berarti nilainya dialokasikan sekali saat package dimuat (preallocation), bukan dibuat ulang setiap kali error terjadi.

Membuat Error Dinamis dengan fmt.Errorf #

Ketika pesan harus memuat data — angka, nama berkas, atau masukan pengguna — gunakan fmt.Errorf dengan format verb:

go
return "", fmt.Errorf("panjang %d melebihi batas 4096", panjang)

Fungsi ini merangkai pesan persis seperti fmt.Printf, tetapi hasilnya dikembalikan sebagai nilai error, bukan dicetak ke layar. Kombinasi %q untuk string dan %d untuk angka membuat pesan tetap informatif tanpa perlu penggabungan string manual.

Konvensi Penulisan Pesan Error #

Ekosistem Go menganut konvensi pesan error yang konsisten. Poin-poinnya singkat:

  • Tulis pesan dengan huruf kecil (lowercase) dan tanpa tanda titik di akhir, karena pesan biasanya digabung atau dibungkus dengan konteks tambahan oleh lapisan di atasnya.
  • Jangan menulis awalan seperti error: — status error sudah jelas dari tipenya.
  • Sebutkan konteks secara ringkas pada bagian depan pesan, misalnya panjang 8192 melebihi batas 4096.

Program Utuh #

Berkas membuat-error-demo.go di bawah halaman mempraktikkan kedua konstruktor dalam satu program:

go
package main

import (
	"errors"
	"fmt"
)

// ErrKoneksiTertutup dibuat sekali di level package.
var ErrKoneksiTertutup = errors.New("koneksi sudah tertutup")

func bacaBaris(aktif bool, panjang int) (string, error) {
	if !aktif {
		return "", ErrKoneksiTertutup
	}
	if panjang > 4096 {
		return "", fmt.Errorf("panjang %d melebihi batas 4096", panjang)
	}
	return "baris contoh", nil
}

func main() {
	teks, err := bacaBaris(false, 100)
	fmt.Printf("teks=%q err=%v\n", teks, err)

	teks, err = bacaBaris(true, 8192)
	fmt.Printf("teks=%q err=%v\n", teks, err)

	teks, err = bacaBaris(true, 128)
	fmt.Printf("teks=%q err=%v\n", teks, err)

	a := errors.New("format berkas rusak")
	b := errors.New("format berkas rusak")
	fmt.Println("kesamaan nilai:", a == b)
	fmt.Println("kesamaan pesan:", a.Error() == b.Error())
}

Jalankan program dari direktori chapter dengan perintah berikut:

bash
go run membuat-error-demo.go

Output yang Dihasilkan:

text
teks="" err=koneksi sudah tertutup
teks="" err=panjang 8192 melebihi batas 4096
teks="baris contoh" err=<nil>
kesamaan nilai: false
kesamaan pesan: true

Mari kita telaah baris demi baris program di atas:

  1. Baris 9 (var ErrKoneksiTertutup): sentinel dibuat sekali saat package dimuat; seluruh pemanggilan berbagi nilai yang sama sehingga identitasnya stabil untuk dibandingkan.
  2. Baris 11-19 (func bacaBaris): fungsi mengembalikan (string, error); dua jalur gagal masing-masing memakai konstruktor berbeda sesuai sifat pesannya.
  3. Baris 12-14 (if !aktif ... ErrKoneksiTertutup): kondisi gagal statis mengembalikan sentinel, bukan membuat error baru — hemat alokasi dan mudah dibandingkan.
  4. Baris 15-17 (if panjang > 4096 ... fmt.Errorf): pesan dinamis memuat angka panjang lewat verb %d, sehingga pemanggil tahu nilai mana yang melanggar batas.
  5. Baris 22-29 (func main): tiga pemanggilan mencetak pasangan hasil dan error dengan fmt.Printf verb %q serta %v; verb %v pada error memanggil method Error().
  6. Baris 31-34 (a dan b): dua errors.New dengan teks sama dibandingkan dua cara — perbandingan nilai menghasilkan false, perbandingan teks Error() menghasilkan true.

Konstruktor errors.New dan fmt.Errorf menutup kebutuhan dasar, tetapi pemanggil kadang perlu bertanya lebih dari sekadar “gagal atau tidak”: apakah gagal karena data tidak ada, atau karena data tidak valid? Chapter berikutnya, Sentinel Error , memperkenalkan pola error acuan yang bisa dibandingkan dengan errors.Is.

Referensi #

Berkas Sumber

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

membuat-error-demo.go

Unduh berkas
go
package main

import (
	"errors"
	"fmt"
)

// ErrKoneksiTertutup dibuat sekali di level package.
var ErrKoneksiTertutup = errors.New("koneksi sudah tertutup")

func bacaBaris(aktif bool, panjang int) (string, error) {
	if !aktif {
		return "", ErrKoneksiTertutup
	}
	if panjang > 4096 {
		return "", fmt.Errorf("panjang %d melebihi batas 4096", panjang)
	}
	return "baris contoh", nil
}

func main() {
	teks, err := bacaBaris(false, 100)
	fmt.Printf("teks=%q err=%v\n", teks, err)

	teks, err = bacaBaris(true, 8192)
	fmt.Printf("teks=%q err=%v\n", teks, err)

	teks, err = bacaBaris(true, 128)
	fmt.Printf("teks=%q err=%v\n", teks, err)

	a := errors.New("format berkas rusak")
	b := errors.New("format berkas rusak")
	fmt.Println("kesamaan nilai:", a == b)
	fmt.Println("kesamaan pesan:", a.Error() == b.Error())
}