Data yang masuk ke any atau interface lain pada akhirnya harus keluar kembali dalam bentuk tipe konkret: angka yang dijumlahkan, teks yang dipotong, struct yang field-nya dibaca. Operasi mengeluarkan nilai dari interface dinamakan type assertion. Bentuknya kecil — satu pasang tanda kurung setelah nilai interface — tetapi konsekuensinya besar: satu bentuk assertion bisa menghentikan program lewat panic, sementara bentuk lainnya aman sepenuhnya. Chapter ini membedah kedua bentuk tersebut, memperlihatkan panic-nya secara nyata, lalu menunjukkan assertion yang menyasar interface, bukan hanya tipe konkret.
Dua Bentuk Type Assertion #
Bentuk pertama mengembalikan satu nilai:
v := x.(int)Statement ini menyatakan: “dynamic type dari x adalah int, keluarkan dynamic value-nya”. Jika dugaan benar, v berisi nilai integer siap pakai. Jika dynamic type ternyata string, program panic saat runtime — bukan gagal kompilasi, karena compiler tidak tahu isi pasangan (dynamic type, dynamic value) sebelum program berjalan.
Bentuk kedua, comma-ok, mengembalikan dua nilai:
v, ok := x.(int)Dalam bentuk ini kegagalan tidak lagi mematikan program: ok bernilai false dan v diisi zero value tipe sasaran (0 untuk int). Pola ini semangatnya sama dengan pemeriksaan elemen map v, ok := m[k] dan penerimaan channel v, ok := <-ch, sehingga terasa alami dikombinasikan dengan if:
if v, ok := x.(int); ok {
// v hanya hidup di dalam blok ini, dengan tipe int yang sudah pasti
}Panic di Dunia Nyata #
Berkas error-assertion.go sengaja memakai bentuk satu nilai dengan tipe yang salah. Jalankan berkas tersebut dan perhatikan apa yang terjadi:
package main
import "fmt"
func main() {
var nilai any = "bukan angka"
// Bentuk satu nilai: tipe tidak cocok menyebabkan panic saat runtime.
angka := nilai.(int)
fmt.Println("baris ini tidak pernah tercetak:", angka)
}Output yang Dihasilkan:
panic: interface conversion: interface {} is string, not int
exit status 2Di antara kedua baris tersebut Go juga mencetak goroutine 1 [running]: beserta stack trace yang memuat path berkas dan offset memori; bagian itu dihilangkan karena isinya berbeda di setiap mesin. Proses berhenti dengan exit status 2 dan fmt.Println di baris terakhir tidak pernah dieksekusi — panic memutus alur di titik assertion terjadi. Pesan interface conversion menyebutkan dua fakta penting: dynamic type sebenarnya (string) dan tipe yang diduga (int).
Assertion ke Interface #
Sasaran assertion tidak harus tipe konkret. x.(Stringer) memeriksa apakah dynamic type dari x mengimplementasikan interface Stringer; jika ya, hasil assertion bertipe Stringer sehingga method String() bisa dipanggil tanpa tahu struct aslinya. Kegagalan tetap mengikuti aturan yang sama: panic pada bentuk satu nilai, ok bernilai false pada bentuk comma-ok. Teknik ini menjadi tulang punggung pemeriksaan seperti errors.As yang berburu tipe error tertentu di dalam rantai error.
Program Demo #
Berkas assertion-demo.go merangkum bentuk comma-ok, kombinasi if, dan assertion ke interface dalam satu program:
package main
import "fmt"
// Stringer adalah tiruan kecil dari fmt.Stringer.
type Stringer interface {
String() string
}
type Sensor struct {
Nama string
Suhu float64
}
func (s Sensor) String() string {
return fmt.Sprintf("%s: %.1f derajat", s.Nama, s.Suhu)
}
func main() {
var nilai any = Sensor{Nama: "Ruang Server", Suhu: 21.5}
// Bentuk comma-ok: aman, ok bernilai false tanpa panic.
sensor, ok := nilai.(Sensor)
fmt.Println("ok:", ok, "sensor:", sensor)
// Kombinasi comma-ok dalam if untuk cabang yang hanya dipakai bila cocok.
if s, ok := nilai.(Sensor); ok {
fmt.Println("suhu ruangan:", s.Suhu)
} else {
fmt.Println("nilai bukan Sensor")
}
// Type assertion ke interface: apakah tipe dinamis mengimplementasikan Stringer?
if s, ok := nilai.(Stringer); ok {
fmt.Println(s.String())
}
// Tipe yang tidak cocok cukup menghasilkan ok = false.
if teks, ok := nilai.(string); ok {
fmt.Println("teks:", teks)
} else {
fmt.Println("nilai bukan string, lanjut tanpa panic")
}
}Output yang Dihasilkan:
ok: true sensor: Ruang Server: 21.5 derajat
suhu ruangan: 21.5
Ruang Server: 21.5 derajat
nilai bukan string, lanjut tanpa panicMari kita telaah baris demi baris program di atas:
- Baris 6–8 (
type Stringer interface): interface buatan sendiri dengan satu method; menjadi sasaran assertion ke interface di baris 34. - Baris 15–17 (
func (s Sensor) String): method value receiver ini membuatSensorsekaligus memenuhiStringer— dua kontrak dengan satu method. - Baris 20 (
var nilai any = Sensor{...}): struct dibungkus ke dalamany; sejak baris ini dynamic type-nyamain.Sensor. - Baris 23–24 (
sensor, ok := nilai.(Sensor)): assertion comma-ok berhasil;okbernilaitruedansensorbertipeSensorpenuh, bukan lagiany. - Baris 27–31 (
if s, ok := ...; ok): variabelsdanokhanya hidup di dalam blokif, pola yang menjaga scope tetap sempit. - Baris 34–36 (
nilai.(Stringer)): assertion ke interface berhasil karena dynamic typeSensormengimplementasikanString(); hasilnya dipanggil sebagais.String(). - Baris 39–43 (
nilai.(string)): tipe tidak cocok,okbernilaifalse, cabangelsejalan, dan program tetap hidup — inilah perbedaan nyata denganerror-assertion.go.
Type assertion memeriksa satu tipe pada satu waktu. Begitu cabang per tipe bertambah banyak, menumpuk if bertingkat menjadi tidak praktis — dan di situlah type switch mengambil alih, topik chapter berikutnya.
Referensi #
- Effective Go: Interface conversions — pola konversi dan assertion antar interface.
- Spesifikasi Go: Interface types — aturan resmi method set dan assertion.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
assertion-demo.go
Unduh berkaspackage main
import "fmt"
// Stringer adalah tiruan kecil dari fmt.Stringer.
type Stringer interface {
String() string
}
type Sensor struct {
Nama string
Suhu float64
}
func (s Sensor) String() string {
return fmt.Sprintf("%s: %.1f derajat", s.Nama, s.Suhu)
}
func main() {
var nilai any = Sensor{Nama: "Ruang Server", Suhu: 21.5}
// Bentuk comma-ok: aman, ok bernilai false tanpa panic.
sensor, ok := nilai.(Sensor)
fmt.Println("ok:", ok, "sensor:", sensor)
// Kombinasi comma-ok dalam if untuk cabang yang hanya dipakai bila cocok.
if s, ok := nilai.(Sensor); ok {
fmt.Println("suhu ruangan:", s.Suhu)
} else {
fmt.Println("nilai bukan Sensor")
}
// Type assertion ke interface: apakah tipe dinamis mengimplementasikan Stringer?
if s, ok := nilai.(Stringer); ok {
fmt.Println(s.String())
}
// Tipe yang tidak cocok cukup menghasilkan ok = false.
if teks, ok := nilai.(string); ok {
fmt.Println("teks:", teks)
} else {
fmt.Println("nilai bukan string, lanjut tanpa panic")
}
}
error-assertion.go
Unduh berkaspackage main
import "fmt"
func main() {
var nilai any = "bukan angka"
// Bentuk satu nilai: tipe tidak cocok menyebabkan panic saat runtime.
angka := nilai.(int)
fmt.Println("baris ini tidak pernah tercetak:", angka)
}