Menu

Type Assertion di Golang: x.(T), Comma-ok, dan Type Switch

Type assertion mengambil nilai konkret dari sebuah interface. Pelajari x.(T), bentuk comma-ok yang tidak pernah panic, assertion ke interface lain, type switch, dan errors.As untuk error yang dibungkus.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

x.(T): mengambil nilai dari interface

Nilai interface menyembunyikan tipe konkret yang ada di dalamnya. Type assertion x.(T) meminta tipe itu kembali.

Output:

gopher 6
0 false
string of length 6

x harus bertipe interface. Assertion pada tipe konkret gagal dikompilasi: invalid operation: s (variable of type string) is not an interface.

Bentuk satu nilai bisa panic

Kalau assertion-nya salah, bentuk satu nilai akan panic dengan pesan yang menyebut kedua tipe:

Output:

recovered: interface conversion: interface {} is int, not string

Pakai bentuk satu nilai hanya kalau tipe yang berbeda berarti kesalahan pemrograman yang memang ingin kamu hentikan dengan crash. Di tempat lain, pakai comma-ok. Saat gagal, comma-ok memberi zero value dari T dan false.

Assertion pada interface yang nil juga gagal: var v any; v.(string) akan panic dengan interface conversion: interface {} is nil, not string, dan bentuk comma-ok mengembalikan "", false.

Assertion ke interface lain

T boleh berupa tipe interface. Assertion-nya lalu berhasil jika nilai dinamisnya mengimplementasikan T, dan hasilnya tetap menyimpan nilai dinamis yang sama. Dengan cara inilah pustaka standar memeriksa kemampuan opsional.

io.Copy memeriksa apakah sumbernya mengimplementasikan io.WriterTo dan memakainya kalau iya. fmt memeriksa Stringer dan error. Pola ini membuat interface kecil tetap kecil, sementara pemanggil tetap mendapat manfaat dari implementasi yang lebih kaya.

Type switch

Ketika sebuah nilai bisa berupa salah satu dari beberapa tipe, type switch menggantikan rangkaian assertion. x.(type) hanya sah di dalam switch.

Output:

hi
integer 7
integer 8
3.14
nil
error: boom
unhandled []int

Aturan yang perlu kamu tahu:

  • Di case dengan satu tipe, x bertipe itu. Di case yang berisi beberapa tipe, dan di default, x bertipe interface aslinya (any di sini).
  • Case diperiksa berurutan. Taruh interface yang lebih spesifik sebelum yang lebih umum, karena sebuah nilai bisa memenuhi beberapa interface.
  • case nil hanya cocok dengan interface yang nil, bukan interface yang berisi pointer nil.
  • Tidak ada fallthrough di type switch.

errors.As: assertion untuk error yang dibungkus

Error sering dibungkus dengan konteks: fmt.Errorf("load config: %w", err). Type assertion langsung hanya melihat error terluar dan melewatkan error di dalamnya. errors.As menelusuri rantainya.

Output:

type assertion finds it: false
errors.As finds it: open /no/such/file

Pakai type assertion pada error hanya kalau kamu tahu error-nya tidak dibungkus, yang dalam praktiknya hampir tidak pernah. Halaman custom error membahas errors.As, errors.Is, dan cara mendefinisikan tipe error sendiri.

Assertion vs konversi vs generic

Kamu punyaKamu inginPakai
intfloat64konversi: float64(n)
any yang berisi intint-nyaassertion: v.(int)
any dengan beberapa kemungkinan tipebercabang berdasarkan tipetype switch
error yang mungkin dibungkustipe error tertentuerrors.As
fungsi yang bekerja untuk banyak tipekeamanan saat kompilasigeneric

Kode yang penuh any dan type switch sering menjadi tanda bahwa generic atau interface yang tepat akan menyatakan maksudnya dengan lebih baik dan menangkap kesalahan saat kompilasi.

Kesalahan umum

  • Memakai bentuk yang bisa panic pada data yang tidak tepercaya. JSON hasil decode, nilai map bertipe any, input plugin: selalu pakai comma-ok.
  • Assertion ke tipe angka yang salah. Angka JSON di-decode ke any sebagai float64, jadi v.(int) gagal pada angka itu.
  • Assertion ke tipe nilai padahal yang disimpan adalah pointer. Kalau interface-nya berisi *User, maka v.(User) gagal. Lakukan assertion v.(*User).
  • Type assertion pada error. Pakai errors.As.

Pertanyaan yang sering diajukan

Apa itu type assertion di Go?

Ekspresi x.(T) dengan x berupa nilai interface. Jika T adalah tipe konkret, ekspresi ini mengembalikan nilai yang disimpan di x sebagai T. Jika T adalah tipe interface, ekspresi ini memeriksa apakah nilai yang disimpan juga mengimplementasikan T. Bentuk dengan satu nilai akan panic kalau pemeriksaannya gagal; bentuk dengan dua nilai, v, ok := x.(T), melaporkannya di ok.

Bagaimana cara memeriksa tipe sebuah nilai interface di Go?

Pakai type switch: switch v := x.(type) { case int: ...; case string: ...; default: ... }. Di dalam setiap case, v bertipe sesuai case itu. Untuk satu tipe saja, assertion comma-ok s, ok := x.(string) lebih singkat. fmt.Printf("%T", x) mencetak nama tipenya untuk keperluan debugging.

Apa bedanya type assertion dan konversi tipe di Go?

Konversi T(x) mengubah nilai dari satu tipe ke tipe lain, seperti float64(n); compiler yang memutuskan apakah konversi itu diizinkan, dan konversi tidak bisa gagal saat program berjalan. Assertion x.(T) hanya bekerja pada nilai interface dan memeriksa saat program berjalan tipe apa yang tersimpan di dalamnya. Kamu tidak bisa menulis int(x) untuk any yang berisi int; kamu butuh x.(int).

Apakah sebaiknya saya memakai type assertion untuk memeriksa tipe error?

Tidak. Pakai errors.As(err, &target). Assertion langsung err.(*MyError) hanya melihat error terluar, jadi assertion itu gagal begitu error-nya dibungkus dengan fmt.Errorf("...: %w", err). errors.As menelusuri rantai pembungkusnya.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai