Menu
CoddyTech

errors.Is() dan errors.As()

Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 56 dari 107.

Saat error dibungkus, pemeriksaan kesetaraan sederhana seperti err == ErrNotFound tidak lagi berfungsi. Package errors menyediakan dua fungsi untuk memeriksa rantai error yang dibungkus: errors.Is() dan errors.As().

errors.Is() memeriksa apakah ada error dalam rantai yang cocok dengan sentinel error tertentu:

import "errors"

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

func FindUser(id int) error {
    return fmt.Errorf("database lookup failed: %w", ErrNotFound)
}

err := FindUser(42)
if errors.Is(err, ErrNotFound) {
    fmt.Println("User doesn't exist")
}

Meskipun error yang dikembalikan dibungkus, errors.Is() mengurai rantainya dan menemukan ErrNotFound di dalamnya.

errors.As() memeriksa apakah ada error dalam rantai yang cocok dengan tipe tertentu, lalu mengekstraknya:

type ValidationError struct {
    Field string
}

func (e *ValidationError) Error() string {
    return "validation failed: " + e.Field
}

err := fmt.Errorf("request failed: %w", &ValidationError{Field: "email"})

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

Gunakan errors.Is() saat memeriksa error sentinel, dan errors.As() saat kamu perlu mengakses field dari tipe error kustom. Kedua fungsi ini menelusuri seluruh rantai error, sehingga penting untuk menangani error yang dibungkus dengan benar.

challenge icon

Tantangan

Mudah

Mari buat sistem pemrosesan file yang menunjukkan cara memeriksa rantai error yang dibungkus dengan benar menggunakan errors.Is() dan errors.As(). Kamu akan membuat error yang dibungkus saat melewati lapisan berbeda, lalu menggunakan fungsi-fungsi ini untuk mengidentifikasi dan mengambil informasi darinya.

Kamu akan menyusun kodemu dalam dua file:

  • errors.go: Tentukan infrastruktur error untuk sistem file-mu.

    Buat error sentinel:

    • ErrPermissionDenied dengan pesan "permission denied"

    Buat tipe error khusus:

    • struct FileError dengan field Filename (string) dan Operation (string)
    • method Error()-nya harus mengembalikan: [Operation] failed on file: [Filename]

    Implementasikan dua fungsi yang menyimulasikan operasi file dan membungkus error:

    • ReadFile(filename string) error - Jika filename adalah "secret.txt", kembalikan ErrPermissionDenied. Jika filename adalah "missing.txt", kembalikan *FileError dengan Operation "read" dan Filename yang diberikan. Jika tidak, kembalikan nil.
    • ProcessFile(filename string) error - Memanggil ReadFile. Jika sebuah error dikembalikan, bungkus menggunakan fmt.Errorf dengan format "processing failed: %w". Jika tidak, kembalikan nil.
  • main.go: Baca nama file dari input dan panggil ProcessFile. Gunakan errors.Is() dan errors.As() untuk memeriksa rantai error yang dibungkus dan mencetak pesan yang sesuai berdasarkan isinya.

Input berikut akan diberikan:

  • Baris 1: Nama file yang akan diproses

Tangani hasilnya dengan memeriksa rantai error:

  • Jika errors.Is() menemukan ErrPermissionDenied dalam rantai: cetak pesan error lengkap, lalu cetak Access denied - check file permissions pada baris baru
  • Jika errors.As() menemukan *FileError dalam rantai: cetak pesan error lengkap, lalu cetak File issue: [Filename] during [Operation] pada baris baru
  • Jika tidak terjadi error: cetak File '[filename]' processed successfully

Misalnya, jika diberi secret.txt, output-mu seharusnya seperti ini:

processing failed: permission denied
Access denied - check file permissions

Jika diberi missing.txt, output-mu seharusnya seperti ini:

processing failed: read failed on file: missing.txt
File issue: missing.txt during read

Jika diberi data.txt, output-mu seharusnya seperti ini:

File 'data.txt' processed successfully

Perhatikan bahwa meskipun error dibungkus oleh ProcessFile, kamu tetap dapat mendeteksi error sentinel asli dengan errors.Is() dan mengambil tipe error khusus dengan errors.As(). Fungsi-fungsi ini menelusuri seluruh rantai error untuk menemukan yang kamu cari.

Coba sendiri

package main

import (
	"errors"
	"fmt"
)

func main() {
	// Baca nama file dari input
	var filename string
	fmt.Scanln(&filename)

	// Panggil ProcessFile dengan nama file tersebut
	err := ProcessFile(filename)

	// TODO: Tangani hasilnya dengan memeriksa rantai error
	// 
	// Gunakan errors.Is() untuk memeriksa apakah ErrPermissionDenied ada dalam rantai error:
	// - Jika ditemukan: cetak error lengkap, lalu "Access denied - check file permissions"
	//
	// Gunakan errors.As() untuk memeriksa apakah *FileError ada dalam rantai error:
	// - Jika ditemukan: cetak error lengkap, lalu "File issue: [Filename] during [Operation]"
	//
	// Jika tidak ada error: cetak "File '[filename]' processed successfully"

	_ = errors.Is // petunjuk: gunakan errors.Is()
	_ = errors.As // petunjuk: gunakan errors.As()
	_ = err
}
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Objek

Latihan sendiri: Compiler Go online