在 php、java 語言反射機制在框架當中常常運用,用於提供實體化物件
在 golang 可以在運行時動態獲取變數的各種信息,比如說變數的類型、類別
Package reflect implements run-time reflection, allowing a program to manipulate objects with arbitrary types. The typical use is to take a value with static type interface{} and extract its dynamic type information by calling TypeOf, which returns a Type.
A call to ValueOf returns a Value representing the run-time data. Zero takes a Type and returns a Value representing a zero value for that type.
使用 reflect.TypeOf() 可以獲得任意值得類型對象
package main
import (
"fmt"
"reflect"
)
func reflectType(x interface{}) {
v := reflect.TypeOf(x)
fmt.Printf("type:%v\n", v)
//如果 array、slice、map、pointer name 為空
fmt.Printf("name:%v\n", v.Name())
fmt.Printf("kind:%v\n", v.Kind())
}
func main() {
var a float32 = 3.14
reflectType(a)
var b int64 = 100
reflectType(b)
var c = make([]int, 10, 10)
reflectType(c)
}
使用 reflect.ValueOf() 可以獲得任意值得 value 對象
package main
import (
"fmt"
"reflect"
)
func reflectValue(x interface{}) {
fmt.Println("x :", x)
v := reflect.ValueOf(x)
fmt.Printf("value :%v\n", v)
fmt.Printf("kind:%v\n", v.Kind())
}
func main() {
var a float32 = 3.14
reflectValue(a)
var b int64 = 100
reflectValue(b)
var c = make([]int, 10, 10)
reflectValue(c)
}
想要在 func 中透過反射修改變數值,需注意函數參數傳遞是 call by value ,必須傳遞變數的 address 才能修改變數值,而反射中使用 Elem() 方法來獲取 pointer 對應的值
package main
import (
"fmt"
"reflect"
)
func reflectSetValue(x interface{}) {
v := reflect.ValueOf(x)
fmt.Println(v.Elem())
if v.Elem().Kind() == reflect.Int64 {
v.Elem().SetInt(200)
}
}
func main() {
var b int64 = 100
//需傳 adress 否則會panic
reflectSetValue(&b)
fmt.Println(b)
}
package main
import (
"fmt"
"reflect"
)
type Test struct {
}
func (t Test) String() {
}
func main() {
var a *int
fmt.Println("var a *int isNil", reflect.ValueOf(a).IsNil())
fmt.Println("nil isValid:", reflect.ValueOf(nil).IsValid())
b := Test{}
fmt.Println("struct 是否存在 'abc' feild ", reflect.ValueOf(b).FieldByName("abc").IsValid())
fmt.Println("struct 是否存在 'abc' method", reflect.ValueOf(b).MethodByName("Abc").IsValid())
fmt.Println("struct 是否存在 'String' method", reflect.ValueOf(b).MethodByName("String").IsValid())
c := map[string]int{}
c["測試2"] = 5
fmt.Println("map key是否存在 '測試' ", reflect.ValueOf(c).MapIndex(reflect.ValueOf("測試")).IsValid())
fmt.Println("map key是否存在 '測試2' ", reflect.ValueOf(c).MapIndex(reflect.ValueOf("測試2")).IsValid())
}
package main
import (
"fmt"
"reflect"
)
type student struct {
Name string `json:"name"`
Score int `json:"score "`
}
func main() {
stu1 := student{
Name: "小王子",
Score: 90,
}
t := reflect.TypeOf(stu1)
fmt.Println("struct Name:", t.Name(), "type 為", t.Kind())
fmt.Println("student struct filed count:", t.NumField())
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fmt.Printf("student field name:%s index:%d type:%v json tag :%v\n", field.Name, field.Index, field.Type, field.Tag.Get("json"))
}
if scoreField, ok := t.FieldByName("Score"); ok {
fmt.Println("獲取 student struct Score feild 成功")
fmt.Printf("field name 為 %s \n", scoreField.Name)
fmt.Printf("field index 為 %d \n", scoreField.Index)
fmt.Printf("field type 為 %v \n", scoreField.Type)
fmt.Printf("field json tag 為 %s \n", scoreField.Tag.Get("json"))
}
}
使用 json package 中 Marshal func 可以將 struct 當中的 filed 轉成 json 字串
package main
import (
"encoding/json"
"fmt"
)
type student struct {
Name string `json:"name"`
Score int `json:"score "`
}
func main() {
stu1 := student{
Name: "小王子",
Score: 90,
}
if s, err := json.Marshal(stu1); err == nil {
fmt.Println(string(s))
}
}