Mengetik interface{} sepuluh kali dalam satu file terasa seperti hukuman: karakternya banyak, maksudnya tidak langsung terbaca. Tim Go menjawab keluhan ini pada Go 1.18 dengan memperkenalkan any — nama pendek yang kini menjadi cara baku menulis tipe “nilai apa saja”. Chapter ini membuktikan bahwa any dan interface{} adalah tipe yang sama persis, memetakan titik-titik di mana standard library memakainya, lalu menarik garis tegas antara pemakaian yang tepat dan pemakaian yang menandakan desain lemah.
any Adalah Alias, Bukan Tipe Baru #
Deklarasi resminya ada di package builtin dan hanya satu baris:
type any = interface{}Tanda sama dengan di tengah deklarasi itu adalah type alias: any bukan tipe baru, melainkan nama lain untuk interface{}. Karena any dan interface{} adalah tipe yang sama, variabel any bisa dibandingkan, di-assign, dan dikirim ke parameter interface{} tanpa konversi apa pun. Demikian pula sebaliknya: kode lama yang memakai interface{} tetap kompatibel dengan kode baru yang memakai any.
Kedalaman maknanya pun tidak berubah: variabel any tetap menyimpan pasangan (dynamic type, dynamic value) sebagaimana dibahas pada chapter Empty Interface
. Alias ini murni urusan keterbacaan, diperkenalkan bersamaan dengan fitur generics pada Go 1.18 yang menjadikan any juga berperan sebagai constraint paling longgar untuk type parameter.
any di Standard Library #
Sejak Go 1.21, standard library secara sistematis memakai any pada signature publiknya. Dua contoh yang paling sering Anda jumpai:
func Println(a ...any) (n int, err error) // package fmt
func Info(msg string, args ...any) // package log/slogSignature fmt.Println yang dulu ditulis a ...interface{} kini tampil sebagai a ...any di dokumentasi — keduanya kompatibel biner karena tipenya memang sama. Package log/slog (baru di Go 1.21) memakai args ...any untuk menerima pasangan key-value bertipe campuran, dan encoding/json mendekode objek menjadi map[string]any. Ketiga kasus ini memiliki pola yang sama: any dipakai sebagai wadah data transit yang tipenya baru diketahui saat runtime.
Batas Pemakaian: Fleksibilitas atau Desain Lemah #
any yang tepat dipakai biasanya hidup di tepi program — titik masuk data dari luar (JSON, konfigurasi, log) yang memang belum punya tipe. Setelah data masuk, kode bertanggung jawab mengubahnya menjadi tipe konkret atau struct domain secepat mungkin.
Masalah muncul ketika any menjalar ke dalam logika bisnis. Operasi aritmetika langsung ditolak compiler, sehingga kode dipenuhi type assertion dan type switch hanya untuk melakukan pekerjaan paling sederhana. Kalau Anda menemukan fungsi internal bertanda any yang isinya bercabang per tipe, itu bukan fleksibilitas — itu tanggung jawab tipe yang terdorong ke runtime, padahal compiler sebenarnya sanggup memikulnya lewat generics atau parameter bertipe konkret.
Program Demo #
Berkas any-demo.go memakai any sesuai perannya: menampung konfigurasi bertipe campuran sebagai data transit:
package main
import "fmt"
// Konfigurasi menyimpan nilai beragam tipe sebagai data transit.
type Konfigurasi map[string]any
func main() {
konfig := Konfigurasi{
"host": "localhost",
"port": 8080,
"debug": true,
"retries": 3,
}
// fmt mengurutkan kunci map sehingga output tetap deterministik.
fmt.Println(konfig)
for _, kunci := range []string{"host", "port", "debug"} {
fmt.Printf("%s bertipe %T\n", kunci, konfig[kunci])
}
// any dan interface{} adalah nama untuk tipe yang sama persis.
var a any = "belajar"
var b interface{} = "belajar"
fmt.Println("a == b:", a == b)
}Output yang Dihasilkan:
map[debug:true host:localhost port:8080 retries:3]
host bertipe string
port bertipe int
debug bertipe bool
a == b: trueMari kita telaah baris demi baris program di atas:
- Baris 6 (
type Konfigurasi map[string]any): mendefinisikan tipe map dengan nilaiany; satu map kini menampung string, int, dan bool sekaligus. - Baris 9–14 (
konfig := Konfigurasi{...}): composite literal mengisi empat kunci dengan tipe berbeda; setiap nilai dibungkus pasangan (dynamic type, dynamic value). - Baris 17 (
fmt.Println(konfig)): mencetak seluruh map;fmtmengurutkan kunci map sejak Go 1.12 sehingga hasilnya deterministik dan aman ditampilkan. - Baris 19–21 (
for _, kunci := range ...): iterasi dilakukan pada slice kunci yang kita definisikan sendiri urutannya, bukan pada map, demi output yang stabil antar eksekusi. - Baris 20 (
fmt.Printf):%Tmembuktikan tipe asli tiap nilai — string, int, bool — tidak tergantikan menjadi tipe samar. - Baris 24–26 (
var a any ... var b interface{} ...): variabeladanbdideklarasikan dengan dua penulisan berbeda; pembandingana == bmenghasilkantruekarena keduanya bertipe sama dan berisi pasangan yang sama.
any membuat data transit lebih ringkas ditulis, tetapi isinya tetap harus dibuka sebelum bisa diolah. Proses membuka pasangan (dynamic type, dynamic value) itulah yang menjadi topik inti chapter berikutnya: type assertion.
Referensi #
- Spesifikasi Go: Predeclared identifiers
— daftar tipe bawaan termasuk
any. - Go 1.18 Release Notes
— pengenalan
anybersama generics. - Dokumentasi package fmt
— contoh
anypada signature fungsi cetak.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
any-demo.go
Unduh berkaspackage main
import "fmt"
// Konfigurasi menyimpan nilai beragam tipe sebagai data transit.
type Konfigurasi map[string]any
func main() {
konfig := Konfigurasi{
"host": "localhost",
"port": 8080,
"debug": true,
"retries": 3,
}
// fmt mengurutkan kunci map sehingga output tetap deterministik.
fmt.Println(konfig)
for _, kunci := range []string{"host", "port", "debug"} {
fmt.Printf("%s bertipe %T\n", kunci, konfig[kunci])
}
// any dan interface{} adalah nama untuk tipe yang sama persis.
var a any = "belajar"
var b interface{} = "belajar"
fmt.Println("a == b:", a == b)
}