這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
-
- 判斷reflectValue類型並提取資料
- addressable
- 擷取結構體方法的名稱
判斷reflect.Value類型並提取資料
對於reflect.Value類型資料,根據Kind()進行判斷
func formatAtom(v reflect.Value) string { switch v.Kind() { case reflect.Invalid: return "invalid" case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int8, reflect.Int64: return strconv.FormatInt(v.Int(), 10) case reflect.Bool: return strconv.FormatBool(v.Bool()) case reflect.String: return v.String() default: return "no ex" }}
對於其他複雜類型的資料
func display(path string, v reflect.Value) { switch v.Kind() { case reflect.Invalid: fmt.Println("") case reflect.Slice, reflect.Array: for i := 0; i < v.Len(); i++ { display(fmt.Sprintf("%s[%d]", path, i), v.Index(i)) } case reflect.Struct: for i := 0; i < v.NumField(); i++ { fieldPath := fmt.Sprintf("%s[%s]", path, v.Type().Field(i).Name) display(fieldPath, v.Field(i)) } case reflect.Map: for _, key := range v.MapKeys() { display(fmt.Sprintf("[%s][%s]", path, formatAtom(key)), v.MapIndex(key)) } default: fmt.Printf("%s=%s\n", path, formatAtom(v)) }}
注意,對於結構體利用v.Type().Field(i).Name擷取網域名稱,利用v.Field(i)擷取域值。
addressable
利用CanAddr()成員判斷判斷是否addressable。
如下變數d是addressable的,可以利用d.Set(reflect.ValueOf(11))進行賦值。
也可以利用d.Addr().Interface().(*int)轉為指標再設定值,也可以利用d.SetInt(99)賦值:
func addressable_main() { x := 2 d := reflect.ValueOf(&x).Elem() fmt.Println(d.CanAddr()) d.Set(reflect.ValueOf(11)) fmt.Println(x) dp := d.Addr().Interface().(*int) *dp = 12 fmt.Println(x) d.SetInt(99) fmt.Println(x)}
如下:對於int類型的變數x,使用rx.SetString("hello")會引起panic。對於interface{}類型的變數y,既可以使用ry.Set(reflect.ValueOf(3)),也可以使用ry.Set(reflect.ValueOf("hello")),但是使用ry.SetInt(2)會引起panic.
func addressable_main2() { x := 2 rx := reflect.ValueOf(&x).Elem() rx.SetInt(2) rx.Set(reflect.ValueOf(3)) // rx.SetString("hello")//pannic var y interface{} ry := reflect.ValueOf(&y).Elem() ry.Set(reflect.ValueOf(3)) ry.Set(reflect.ValueOf("hello")) fmt.Println(y) // ry.SetInt(2) //panic}func addressable_main3() { stdout := reflect.ValueOf(os.Stdout).Elem() fmt.Println(stdout.Type()) fd := stdout.FieldByName("fd") fmt.Println(fd.Int())}
擷取結構體方法的名稱
由下代碼可以看到v作為reflect.Value類型的變數
可以通過v.Method(i).Type().String()和v.Type().Method(i).Name()
func PrintMethodName(x interface{}) { v := reflect.ValueOf(x) vt := v.Type() fmt.Printf("type %s \n", vt) for i := 0; i < v.NumMethod(); i++ { methType := v.Method(i).Type() fmt.Println("func (%s) :%s :%s\n", vt, vt.Method(i).Name, strings.TrimPrefix(methType.String(), "func")) }}