Reflection
Reflection adalah kemampuan program untuk memeriksa dan memodifikasi strukturnya sendiri saat runtime. Di Go, reflection diimplementasikan melalui package reflect.
Contoh Masalah
Bagaimana cara:
- Memeriksa tipe data saat runtime
- Mengakses dan memodifikasi struct fields
- Membuat fungsi yang bekerja dengan berbagai tipe
Penyelesaian
package main
import (
"fmt"
"reflect"
)
// 1. Struct untuk contoh
type Person struct {
Name string `json:"name" validate:"required"`
Age int `json:"age" validate:"gte=0,lte=130"`
Address string `json:"address,omitempty"`
}
// 2. Interface untuk contoh
type Animal interface {
Speak() string
}
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return "Woof!"
}
// 3. Fungsi untuk memeriksa tipe
func inspectType(x interface{}) {
t := reflect.TypeOf(x)
v := reflect.ValueOf(x)
fmt.Printf("Type: %v\n", t)
fmt.Printf("Kind: %v\n", t.Kind())
if t.Kind() == reflect.Struct {
fmt.Println("\nFields:")
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fmt.Printf(" %s: %v (tag: `%v`)\n",
field.Name,
field.Type,
field.Tag)
}
}
if t.Kind() == reflect.Ptr {
fmt.Printf("Points to: %v\n", t.Elem())
}
fmt.Printf("Value: %v\n", v)
}
// 4. Fungsi untuk memodifikasi nilai
func setValue(x interface{}, fieldName string, value interface{}) error {
v := reflect.ValueOf(x)
if v.Kind() != reflect.Ptr {
return fmt.Errorf("x harus pointer")
}
v = v.Elem()
if v.Kind() != reflect.Struct {
return fmt.Errorf("x harus struct")
}
field := v.FieldByName(fieldName)
if !field.IsValid() {
return fmt.Errorf("field tidak ditemukan: %s", fieldName)
}
val := reflect.ValueOf(value)
if field.Type() != val.Type() {
return fmt.Errorf("tipe tidak sesuai")
}
if !field.CanSet() {
return fmt.Errorf("field tidak bisa diubah")
}
field.Set(val)
return nil
}
// 5. Fungsi untuk membaca tag
func getStructTags(x interface{}) map[string]string {
t := reflect.TypeOf(x)
if t.Kind() != reflect.Struct {
return nil
}
tags := make(map[string]string)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
tags[field.Name] = string(field.Tag)
}
return tags
}
// 6. Fungsi untuk memanggil method
func callMethod(x interface{}, methodName string) ([]reflect.Value, error) {
v := reflect.ValueOf(x)
method := v.MethodByName(methodName)
if !method.IsValid() {
return nil, fmt.Errorf("method tidak ditemukan: %s", methodName)
}
return method.Call(nil), nil
}
// 7. Fungsi untuk membuat instance baru
func createInstance(t reflect.Type) interface{} {
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
return reflect.New(t).Interface()
}
func main() {
// Contoh 1: Inspeksi tipe dasar
fmt.Println("Basic Type Inspection:")
num := 42
str := "hello"
inspectType(num)
inspectType(str)
// Contoh 2: Inspeksi struct
fmt.Printf("\nStruct Inspection:\n")
p := Person{
Name: "John",
Age: 30,
Address: "Jakarta",
}
inspectType(p)
// Contoh 3: Modifikasi nilai
fmt.Printf("\nValue Modification:\n")
p2 := &Person{Name: "Alice", Age: 25}
fmt.Printf("Before: %+v\n", p2)
err := setValue(p2, "Age", 26)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
fmt.Printf("After: %+v\n", p2)
// Contoh 4: Membaca tags
fmt.Printf("\nStruct Tags:\n")
tags := getStructTags(Person{})
for field, tag := range tags {
fmt.Printf("%s: %s\n", field, tag)
}
// Contoh 5: Memanggil method
fmt.Printf("\nMethod Calling:\n")
dog := Dog{Name: "Rex"}
result, err := callMethod(dog, "Speak")
if err != nil {
fmt.Printf("Error: %v\n", err)
} else {
fmt.Printf("Dog says: %v\n", result[0])
}
// Contoh 6: Membuat instance
fmt.Printf("\nInstance Creation:\n")
personType := reflect.TypeOf(Person{})
newPerson := createInstance(personType).(*Person)
fmt.Printf("New person: %+v\n", newPerson)
// Contoh 7: Iterasi fields
fmt.Printf("\nField Iteration:\n")
v := reflect.ValueOf(p)
t := v.Type()
for i := 0; i < v.NumField(); i++ {
field := t.Field(i)
value := v.Field(i)
fmt.Printf("%s: %v\n", field.Name, value.Interface())
}
}
Penjelasan Kode
Basic Reflection
- TypeOf dan ValueOf
- Kind vs Type
- Field inspection
Advanced Features
- Struct tags
- Method calling
- Value modification
Common Uses
- Serialization
- Validation
- Generic programming
Output
Basic Type Inspection:
Type: int
Kind: int
Value: 42
Type: string
Kind: string
Value: hello
Struct Inspection:
Type: main.Person
Kind: struct
Fields:
Name: string (tag: `json:"name" validate:"required"`)
Age: int (tag: `json:"age" validate:"gte=0,lte=130"`)
Address: string (tag: `json:"address,omitempty"`)
Value: {John 30 Jakarta}
Value Modification:
Before: &{Name:Alice Age:25 Address:}
After: &{Name:Alice Age:26 Address:}
Struct Tags:
Name: json:"name" validate:"required"
Age: json:"age" validate:"gte=0,lte=130"
Address: json:"address,omitempty"
Method Calling:
Dog says: Woof!
Instance Creation:
New person: &{Name: Age:0 Address:}
Field Iteration:
Name: John
Age: 30
Address: Jakarta
Tips
- Gunakan reflection dengan bijak
- Perhatikan performa
- Validasi tipe dengan benar
- Handle error dengan baik
- Dokumentasikan penggunaan reflection