Lompati ke konten utama
Modul 10 · Pelajaran 2 dari 547/50 dalam kursus~14 min
Pelajaran modul (2/5)

Penanganan kesalahan idiomatis

Penanganan kesalahan di Go bersifat eksplisit: tidak ada pengecualian, tidak ada coba/tangkap. Setiap fungsi yang bisa gagal mengembalikan error sebagai nilai terakhirnya, dan pemanggil yang memutuskan. Bab ini mengumpulkan pola idiomatik untuk menghasilkan, menyebarkan, dan memeriksa kesalahan dengan cara yang kuat.

Aturan emas

Go
data, err := os.ReadFile(path)
if err != nil {
    return fmt.Errorf("config %s: %w", path, err)
}

Empat prinsip:

  1. error adalah pengembalian terakhir.
  2. Segera periksa dengan if err != nil.
  3. Tambahkan konteks sebelum melakukan propagasi (dengan fmt.Errorf + %w).
  4. Jangan pernah mengabaikan kesalahan: tangani, catat, atau kembalikan.
Go
_ = file.Close() // EXPLICITLY ignored (you know what you're doing)

Kesalahan penjaga

kesalahan penjaga adalah variabel global yang diekspor var ErrXxx = errors.New("...") yang dapat dibandingkan dengan pemanggil:

Go
package store

var ErrNotFound = errors.New("not found")

func Get(key string) (string, error) {
    if !exists(key) {
        return "", ErrNotFound
    }
    // ...
}

Penelepon menggunakan errors.Is (BUKAN ==), yang menjalankan rantai pembungkus:

Go
v, err := store.Get(k)
if errors.Is(err, store.ErrNotFound) {
    // handle 404
}

Contoh standar: io.EOF, sql.ErrNoRows, os.ErrNotExist.

Kesalahan pengetikan khusus

Untuk membawa data terstruktur (kode HTTP, bidang tidak valid, dll.), tentukan jenisnya:

Go
type ValidationError struct {
    Field string
    Msg   string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("%s: %s", e.Field, e.Msg)
}

Penelepon menggunakan errors.As untuk melakukan downcast dengan aman di sepanjang rantai:

Go
var ve *ValidationError
if errors.As(err, &ve) {
    fmt.Println("invalid field:", ve.Field)
}

errors.As menelusuri rantai Unwrap() hingga menemukan kesalahan yang dapat ditetapkan ke penunjuk yang diteruskan.

Membungkus dengan %w

fmt.Errorf dengan kata kerja %w menghasilkan kesalahan yang membungkus kata kerja asli, mempertahankannya untuk errors.Is/errors.As:

Go
if err := db.Query(); err != nil {
    return fmt.Errorf("load users: %w", err)
}

Tanpa %w (menggunakan %v atau %s) Anda mendapatkan string yang lebih kaya tetapi kehilangan rantainya: pemanggil tidak dapat lagi mengenali kesalahan tertentu.

Aturan untuk %w:

  • Hanya satu per fmt.Errorf panggilan (multi-bungkus memerlukan errors.Join).
  • Argumennya HARUS berupa error, bukan string.
  • Tambahkan konteks, jangan duplikat pesan aslinya.
Go
// bad: duplicates
return fmt.Errorf("error: %w", err) // "error: file not found"

// good: useful context
return fmt.Errorf("load config %s: %w", path, err)

errors.Join untuk beberapa kesalahan

Sejak Go 1.20, errors.Join(errs...) menggabungkan beberapa kesalahan menjadi satu sehingga semuanya dapat terdeteksi oleh errors.Is/As:

Go
var errs []error
for _, item := range items {
    if err := process(item); err != nil {
        errs = append(errs, fmt.Errorf("item %s: %w", item.ID, err))
    }
}
if len(errs) > 0 {
    return errors.Join(errs...)
}

Kapan menggunakan panic

Tidak pernah untuk kesalahan yang diharapkan. Hanya dalam tiga kasus:

  1. Bug yang tidak dapat dipulihkan: invarian dilanggar di tempat yang "tidak dapat terjadi" (panic("unreachable")).
  2. Inisialisasi gagal di init()/main() dari program mandiri (konfigurasi penting tidak ada → cepat gagal).
  3. Library API yang mendokumentasikannya secara eksplisit: misalnya, regexp.MustCompile (panik jika polanya tidak valid — dapat diterima karena polanya adalah konstanta waktu pembangunan).

Yang lainnya adalah error. Jangan gunakan panic sebagai pintasan untuk menyebarkan: ini merusak komposisi, melompati defer Close(), dan membuat penelepon kewalahan.

Latihan

Latihan#go.m10.l2.e1
Upaya: 0Memuat…

Selesaikan kesalahan os.ReadFile dengan fmt.Errorf menggunakan kata kerja %w dan tambahkan kontes 'config:' (dengan jalur).

Memuat editor…

Solusi tersedia setelah 3 upaya

Latihan#go.m10.l2.e2
Upaya: 0Memuat…

Kesalahan AS. Apakah untuk memverifikasi apakah ada kesalahan dalam bungkus yang sesuai dengan penjaga ErrNotFound dan cap 'manca!' dalam hal ini.

Memuat editor…

Solusi tersedia setelah 3 upaya

Quiz#go.m10.l2.e3
Siap

Kapan dan secara idiomatis menggunakan kepanikan di perpustakaan Go?

Go
func F(x int) {
  // ??? panic(...)
}
Pilihan jawaban