Go Best Practices - Penanganan kesalahan

Ini adalah artikel pertama dari serangkaian pelajaran yang telah saya pelajari selama beberapa tahun saya bekerja dengan Go in production. Kami menjalankan sejumlah layanan Go dalam produksi di Saltside Technologies (psst, saya merekrut beberapa posisi di Bangalore untuk Saltside) dan saya juga menjalankan bisnis saya sendiri di mana Go merupakan bagian yang tidak terpisahkan.

Kami akan membahas berbagai mata pelajaran, besar dan kecil.

Subjek pertama yang ingin saya bahas dalam seri ini adalah penanganan kesalahan. Ini sering menyebabkan kebingungan dan gangguan bagi pengembang Go baru.

Beberapa latar belakang - Antarmuka kesalahan

Hanya saja kita berada di halaman yang sama. Seperti yang Anda ketahui, kesalahan dalam Go hanyalah apa saja yang mengimplementasikan antarmuka kesalahan. Seperti inilah definisi antarmuka:

ketik antarmuka kesalahan {
    String galat ()
}

Jadi apa pun yang mengimplementasikan metode string Error () dapat digunakan sebagai kesalahan.

Memeriksa kesalahan

Menggunakan struct kesalahan dan pengecekan tipe

Ketika saya mulai menulis Go, saya sering melakukan perbandingan string pesan kesalahan untuk melihat apa jenis kesalahan itu (ya, memalukan untuk dipikirkan tetapi kadang-kadang Anda perlu melihat ke belakang untuk maju).

Pendekatan yang lebih baik adalah dengan menggunakan tipe kesalahan. Jadi, Anda dapat (tentu saja) membuat struct yang mengimplementasikan antarmuka kesalahan dan kemudian melakukan perbandingan jenis dalam pernyataan switch.

Berikut ini contoh implementasi kesalahan.

ketik ErrZeroDivision struct {
    string pesan
}
func NewErrZeroDivision (string pesan) * ErrZeroDivision {
    return & ErrZeroDivision {
        pesan: pesan,
    }
}
func (e * ErrZeroDivision) Error () string {)
    mengembalikan e.message
}

Sekarang kesalahan ini bisa digunakan seperti ini.

func main () {
    hasil, err: = bagi (1.0, 0.0)
    if err! = nil {
        switch err. (type) {
        case * ErrZeroDivision:
            fmt.Println (err.Error ())
        default:
            fmt.Println ("Apa yang baru saja terjadi?")
        }
    }
    fmt.Println (hasil)
}
func divide (a, b float64) (float64, error) {
    jika b == 0,0 {
        return 0,0, NewErrZeroDivision ("Tidak dapat membagi dengan nol")
    }
    mengembalikan a / b, nihil
}

Inilah tautan Go Play untuk contoh lengkap. Perhatikan pola sakelar kesalahan (jenis), yang memungkinkan untuk memeriksa jenis kesalahan yang berbeda dan bukan yang lainnya (seperti perbandingan string atau sesuatu yang serupa).

Menggunakan paket kesalahan dan perbandingan langsung

Pendekatan di atas dapat ditangani secara alternatif menggunakan paket kesalahan. Pendekatan ini direkomendasikan untuk pemeriksaan kesalahan dalam paket di mana Anda memerlukan representasi kesalahan cepat.

var errNotFound = errors.New ("Item tidak ditemukan")
func main () {
    err: = getItem (123) // Ini akan membuang errNotFound
    if err! = nil {
        beralih err {
        case errNotFound:
            log.Println ("Item yang diminta tidak ditemukan")
        default:
            log.Println ("Terjadi kesalahan tidak dikenal")
        }
    }
}

Pendekatan ini kurang baik ketika Anda membutuhkan objek kesalahan yang lebih kompleks dengan mis. kode kesalahan dll. Dalam hal ini Anda harus membuat tipe Anda sendiri yang mengimplementasikan antarmuka kesalahan.

Penanganan kesalahan segera

Kadang-kadang saya menemukan kode seperti di bawah ini (tetapi biasanya dengan lebih banyak bulu di sekitar ..):

func example1 () error {
    err: = call1 ()
    kembali err
}

Intinya di sini adalah bahwa err tidak ditangani dengan segera. Ini adalah pendekatan yang rapuh karena seseorang dapat menyisipkan kode antara err: = call1 () dan return err, yang akan merusak maksud, karena itu mungkin membayangi kesalahan pertama. Dua pendekatan alternatif:

// Perkecil pengembalian dan kesalahan.
func example2 () error {
    return call1 ()
}
// Lakukan penanganan kesalahan eksplisit tepat setelah panggilan.
func example3 () error {
    err: = call1 ()
    if err! = nil {
        kembali err
    }
    kembali nihil
}

Kedua pendekatan di atas baik-baik saja dengan saya. Mereka mencapai hal yang sama, yaitu; jika seseorang perlu menambahkan sesuatu setelah call1 () mereka harus mengurus penanganan kesalahan.

Itu saja untuk hari ini

Nantikan artikel berikutnya tentang Praktik Terbaik Go. Ayo kuat :).

func main () {
    err: = readArticle ("Pergi Praktik Terbaik - Penanganan kesalahan")
    if err! = nil {
        ping ("@ sebdah")
    }
}