guest@blog.cmj.tw: ~/posts $

Go 反射


Deep into the Go

重新描述一下 Go 的 reflect 套件

基礎

透過 reflect.ValueOf 可以得到任意實體 (instance) 的 reflect.Value 物件, 透過這個可以取得物件的類型、值等屬各種屬性。

package main

import (
    "fmt"
    "reflect"
)

func main() {
    object := "Hello, World!"
    value := reflect.ValueOf(object)

    t := value.Type()
    fmt.Println(t)
}

類型

為了能夠可以更彈性的處裡不同類型的物件,我們可以透過 any type 來處理、並且在內部透過 reflect.Type 來做不同類型的處理。

package main

import (
    "fmt"
    "reflect"
)

func handler(object any) {
    value := reflect.ValueOf(object)

    switch value.Kind() {
    case reflect.String:
        fmt.Println("String:", value.String())
    case reflect.Int:
        fmt.Println("Int:", value.Int())
    default:
        fmt.Println("Unknown type")
    }
}

func main() {
    handler("Hello, World!")
    handler(123)
    handler(true)
}

修改內容

在某些情境我們可能需要修改物件的內容,這時候我們可以透過 reflect.ValueElem() 方法來取得指標指向的物件。 接下來可以透過這個指標的操作來修改物件的內容。

package main

import (
    "fmt"
    "reflect"
)

func handler(object any) {
    value := reflect.ValueOf(object)

    if value.Kind() == reflect.Ptr {
        elm := value.Elem()

        switch elm.Kind() {
        case reflect.String:
            elm.SetString("In-place modification")
        case reflect.Int:
            elm.SetInt(9527)
        }
    }
}

func main() {
    str := "Hello, World!"
    handler(&str)
    fmt.Println(str)

    num := 123
    handler(&num)
    fmt.Println(num)
}

複製物件

透過 reflect.ValueInterface() 方法可以取得物件的值,這個方法會回傳一個 interface{} 的物件, 這個物件是一個複製的物件,所以在這個物件上的操作不會影響原本的物件。

package main

import (
    "fmt"
    "reflect"
)

func handler(object any) any {
    value := reflect.ValueOf(object)

    dup := reflect.New(value.Type()).Elem()
    dup.Set(value)

    return dup.Interface()
}

func main() {
    str := "Hello, World!"
    dup := handler(str)
    fmt.Println(str, dup)
}