Menu
CoddyTech

Panic, Defer, dan Recover

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

Meskipun Go menekankan pengembalian error, beberapa situasi memang tidak dapat dipulihkan. Untuk kasus ini, Go menyediakan panic, defer, dan recover: mekanisme untuk menangani keadaan luar biasa.

panic langsung menghentikan eksekusi normal. Kata ini dikhususkan untuk error pemrograman, seperti mengakses indeks di luar batas, bukan untuk error yang sudah diperkirakan, seperti input pengguna yang tidak valid:

func MustGetConfig(key string) string {
    value, exists := config[key]
    if !exists {
        panic("missing required config: " + key)
    }
    return value
}

defer menjadwalkan fungsi agar dijalankan saat fungsi di sekitarnya mengembalikan kendali, baik secara normal maupun karena panic. Pemanggilan yang ditunda dijalankan dalam urutan terbalik (terakhir masuk, pertama keluar):

func ProcessFile() {
    fmt.Println("Opening file")
    defer fmt.Println("Closing file")
    fmt.Println("Processing...")
    // output: Opening file, Processing..., Closing file
}

recover menangkap panic dan mengembalikan eksekusi normal. Ini hanya berfungsi di dalam fungsi yang ditunda:

func SafeOperation() (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("recovered from panic: %v", r)
        }
    }()
    
    riskyOperation()
    return nil
}

Pola ini mengubah panic menjadi error biasa, sehingga programmu dapat terus berjalan. Gunakan pola ini sesekali saja: utamakan mengembalikan error untuk kasus kegagalan yang diperkirakan, dan gunakan panic/recover hanya untuk situasi yang benar-benar luar biasa, seperti state yang rusak atau kondisi yang tidak dapat dipulihkan.

challenge icon

Tantangan

Mudah

Mari buat kalkulator pembagian aman yang menunjukkan cara menggunakan panic, defer, dan recover untuk menangani situasi luar biasa dengan baik. Kalkulatormu akan mencoba operasi berisiko dan mengubah panic menjadi error biasa yang dapat ditangani secara normal.

Kamu akan menyusun kodemu dalam dua file:

  • calculator.go: Buat logika pembagian dengan pemulihan dari panic.

    Buat fungsi Divide yang menerima dua bilangan bulat dan memicu panic dengan pesan "division by zero" jika pembaginya nol. Jika tidak, fungsi ini mengembalikan hasil pembagian berupa bilangan bulat.

    Buat fungsi SafeDivide yang menerima dua bilangan bulat dan mengembalikan hasil berupa bilangan bulat serta error. Fungsi ini harus:

    • Menggunakan defer dengan fungsi anonim untuk memulihkan diri dari panic apa pun
    • Jika panic berhasil dipulihkan, ubah panic tersebut menjadi error dengan format "calculation error: [panic message]"
    • Memanggil fungsi Divide di dalam fungsi ini
    • Mengembalikan hasil dan nil jika berhasil, atau nol dan error jika panic berhasil dipulihkan
  • main.go: Baca dua bilangan bulat dari input dan gunakan SafeDivide untuk melakukan perhitungan dengan aman. Tunjukkan juga penggunaan defer dengan mencetak pesan pembersihan dalam urutan yang benar.

    Fungsi utamamu harus:

    • Mencetak Starting calculation di awal
    • Menggunakan defer untuk menjadwalkan pencetakan Cleanup complete
    • Menggunakan defer lain untuk menjadwalkan pencetakan Releasing resources
    • Memanggil SafeDivide dengan nilai input
    • Mencetak Result: [value] atau Error: [error message] berdasarkan hasilnya

Input berikut akan diberikan:

  • Baris 1: Bilangan bulat pertama (dividend)
  • Baris 2: Bilangan bulat kedua (divisor)

Ingat bahwa pemanggilan yang ditunda dijalankan dalam urutan terbalik (terakhir masuk, pertama keluar), jadi pesan pembersihanmu harus muncul dalam urutan yang berlawanan dengan urutan penundaannya.

Misalnya, jika diberikan 20 dan 4, outputmu harus berupa:

Starting calculation
Result: 5
Releasing resources
Cleanup complete

Dan jika diberikan 10 dan 0, outputmu harus berupa:

Starting calculation
Error: calculation error: division by zero
Releasing resources
Cleanup complete

Coba sendiri

package main

import (
	"fmt"
)

func main() {
	// Baca input
	var dividend, divisor int
	fmt.Scanln(&dividend)
	fmt.Scanln(&divisor)

	// Cetak pesan awal
	fmt.Println("Starting calculation")

	// TODO: Gunakan defer untuk menjadwalkan pesan "Cleanup complete"

	// TODO: Gunakan defer untuk menjadwalkan pesan "Releasing resources"
	// Ingat: pemanggilan yang ditunda dijalankan dalam urutan LIFO (terakhir masuk, pertama keluar)

	// TODO: Panggil SafeDivide dengan nilai input

	// TODO: Cetak "Result: [value]" atau "Error: [error message]"
	// berdasarkan apakah error dikembalikan
}
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