---
id: 548504c5a0b4857763527603f3e1059e
author: snowmerak
title: Any bukanlah Any, melainkan Any adalah Any
description: Dokumen ini menganalisis secara rinci tipe `any` dalam bahasa Go dan struktur internal `EFace`, serta menjelaskan metode penanganan tipe dinamis dengan memanfaatkan paket `reflect` dan type assertion/switch.
language: id
date: 2025-09-30T15:12:53.689280321Z
path: /blog/posts/any-is-not-any-but-any-is-any-z6161856d
category: language
---

## Any

Dalam bahasa Go, tipe any adalah alias dari `interface{}`, sebuah antarmuka ajaib yang dapat menampung semua tipe. Artinya, nilai dengan tipe apa pun dapat ditetapkan ke variabel bertipe any.

```go
var a any
a = 42          // int
a = "hello"     // string
a = true        // bool
a = 3.14        // float64
```

Dengan demikian, tipe any dapat menampung nilai dari berbagai tipe sehingga memungkinkan penulisan kode yang fleksibel. Namun, terdapat beberapa hal yang perlu diperhatikan saat menggunakan tipe any.

### Type Assertion

Untuk menggunakan nilai sebenarnya dari variabel bertipe any, Anda harus menggunakan type assertion (type assertion). Type assertion berperan memberi tahu kompilator bahwa variabel bertipe any tersebut merupakan tipe tertentu.

```go
var a any = "hello"
str, ok := a.(string)
if ok {
    fmt.Println("String value:", str)
} else {
    fmt.Println("Not a string")
}
```

Pada contoh di atas, `a.(string)` menegaskan bahwa `a` bertipe string. Jika `a` bukan bertipe string, maka `ok` akan bernilai false, sehingga program dapat dicegah dari kondisi panic.

### Type Switch

Type switch (type switch) memungkinkan Anda menjalankan perilaku yang berbeda sesuai dengan tipe sebenarnya dari variabel bertipe any. Hal ini berguna ketika harus menangani beberapa tipe.

```go
var a any = 42
switch v := a.(type) {
case int:
    fmt.Println("Integer:", v)
case string:
    fmt.Println("String:", v)
case bool:
    fmt.Println("Boolean:", v)
default:
    fmt.Println("Unknown type")
}
```

Pada contoh di atas, `a.(type)` memeriksa tipe sebenarnya dari `a`, lalu menjalankan case yang sesuai dengan tipe tersebut.

### Reflection

Dengan menggunakan paket reflect dalam bahasa Go, Anda dapat memeriksa dan memanipulasi tipe serta nilai dari variabel bertipe any secara dinamis saat runtime. Hal ini berguna ketika menangani struktur data yang kompleks.

```go
import (
    "fmt"
    "reflect"
)

var a any = 3.14
v := reflect.ValueOf(a)
fmt.Println("Type:", v.Type())
fmt.Println("Value:", v.Float())
```

Pada contoh di atas, paket reflect digunakan untuk memeriksa tipe dan nilai dari `a` saat runtime.

## EFace

Dalam bahasa Go, interface terbagi menjadi dua bentuk utama: EFace (Empty Interface) dan IFace (Interface with Methods). Di antara keduanya, EFace adalah konsep yang sama dengan tipe any yang telah kita bahas sejauh ini.

### Struktur

EFace adalah struktur khusus yang hanya ada di dalam runtime Go, sehingga di sini kita akan membuat mimic (mimic) untuk menanganinya.

```go
type runtimeTypeMimic struct {
	Size_       uintptr
	PtrBytes    uintptr // number of (prefix) bytes in the type that can contain pointers
	Hash        uint32  // hash of type; avoids computation in hash tables
	TFlag       uint8   // extra type information flags
	Align_      uint8   // alignment of variable with this type
	FieldAlign_ uint8   // alignment of struct field with this type
	Kind_       uint8   // enumeration for C
	Equal       func(unsafe.Pointer, unsafe.Pointer) bool
	GCData      *byte
	Str         int32 // string form
	PtrToThis   int32 // type for pointer to this type, may be zero
}

type eFaceMimic struct {
	Type *runtimeTypeMimic
	Data unsafe.Pointer
}
```

EFace memiliki dua field:

- `Type`: pointer yang berisi metadata tentang tipe sebenarnya dari nilai.
- `Data`: pointer yang berisi nilai sebenarnya.

Selain itu, EFace secara internal mengelola informasi tipe melalui struktur `runtimeType`. Struktur ini memuat berbagai metadata, seperti ukuran tipe, alignment, dan nilai hash.

Bagian yang perlu kita perhatikan dalam struktur ini adalah field `Kind_`, `Hash`, dan `Equal`. `Kind_` menunjukkan jenis tipe, sedangkan `Hash` dan `Equal` digunakan untuk membandingkan tipe dan menghitung nilai hash dalam hash table.

### Pembungkusan

Sekarang mari kita bungkus EFace ini agar lebih mudah digunakan untuk melakukan black magic.

```go
type TypeInfo struct {
	Hash  uint32
	TFlag uint8
	Kind  uint8
	Equal func(unsafe.Pointer, unsafe.Pointer) bool
	This  unsafe.Pointer
}

func GetTypeInfo(v any) TypeInfo {
	eface := *(*eFaceMimic)(unsafe.Pointer(&v))
	return TypeInfo{
		Hash:  eface.Type.Hash,
		TFlag: eface.Type.TFlag,
		Kind:  eface.Type.Kind_,
		Equal: eface.Type.Equal,
		This:  eface.Data,
	}
}
```

Fungsi di atas menerima variabel bertipe any, mengekstrak struktur EFace di dalamnya, lalu mengambil informasi tipe dari sana dan mengembalikannya sebagai struktur `TypeInfo`. Dengan `TypeInfo` ini, Anda dapat dengan mudah mengakses nilai hash, jenis, fungsi perbandingan, dan lainnya dari tipe tersebut.

### Penggunaan

Penggunaannya sangat mudah. Cukup berikan variabel bertipe any ke fungsi `GetTypeInfo`.

```go
func main() {
	i := 42
	eface := GetTypeInfo(i)
	fmt.Printf("%+v\n", eface)

	f := 3.14
	eface2 := GetTypeInfo(f)
	fmt.Printf("%+v\n", eface2)

	// Bandingkan kedua nilai menggunakan fungsi Equal dari informasi tipe
	log.Println(eface.Equal(eface.This, eface.This))
	log.Println(eface2.Equal(eface2.This, eface2.This))
	log.Println(eface2.Equal(eface.This, eface2.This))
	log.Println(eface.Equal(eface2.This, eface.This))
}
```

Pada contoh di atas, nilai integer dan floating-point dikirim ke fungsi `GetTypeInfo` untuk mencetak informasi tipe masing-masing, lalu fungsi `Equal` digunakan untuk membandingkan nilai-nilai tersebut. Dengan cara ini, informasi tipe dapat diperoleh dan tipe dibandingkan dengan lebih cepat.

Selain itu, metode ini juga dapat digunakan secara sama untuk struct, pointer, interface, dan lainnya, serta dapat mengatasi masalah typed nil (typed nil) yang cukup sering terjadi. Field `Hash` akan terisi jika tipenya ada, sedangkan `This` akan bernilai 0 jika nil.

## Kesimpulan

EFace memegang peranan penting dalam menangani tipe any di Go saat ini. Melalui EFace, nilai dari berbagai tipe dapat diproses secara fleksibel dan cepat, serta informasi tipe dapat diperoleh dan dimanfaatkan secara rinci. Namun, karena ini merupakan fitur tersembunyi di dalam runtime, perubahan pada spesifikasi bahasa dapat memengaruhinya sehingga perlu diwaspadai.
