Go語言(十五) 反射

反射

變量介紹

  • 變量的內在機制
    • 類型信息,這部分是元信息,是預先定義好的
    • 值類型,這部分是在程序運行過程中動態改變的

反射介紹

  • 反射與空接口
    • 空接口可以存儲任何類型的變量
    • 在程序運行時動態獲取變量的類型信息和值信息,就叫反射
import (
   "fmt"
   "reflect"
)

func TestType(a interface{})  {
   //獲取類型(靜態信息)
   t := reflect.TypeOf(a)
   kind := t.Kind()
   switch kind {
   case reflect.Int:
      fmt.Printf("a is a int\n")
      a = 2
   case reflect.String:
      fmt.Printf("a is a string\n")
   }
   fmt.Printf("t=%v,kind=%v\n\n",t,kind)
}

func TestValue(a interface{}) {
   v := reflect.ValueOf(a)
   //kind := v.Kind()
   t := v.Type()
   switch t.Kind() {
   case reflect.Int:
      fmt.Printf("a is a int\n")
      v.SetInt(10000)
   case reflect.String:
      v.SetString("xxx")
      fmt.Printf("a is a string\n")
   case reflect.Ptr:
      t1 := v.Elem().Type()
      switch (t1.Kind()) {
      case reflect.Int:
         v.Elem().SetInt(100)
         fmt.Printf("ptn is int \n")
      case reflect.String:
         v.Elem().SetString("hello")
         fmt.Printf("ptn is string\n")
      }
      fmt.Printf("a=%v is a point type\n",t1)
   }
   fmt.Printf("v=%v,kind=%v\n\n",v,t)
}

func main() {
   //var a int
   //TestType(a)
   //fmt.Printf("a=%v\n",a)
   //var b string
   //TestType(b)
   var c int
   TestValue(&c)
   var d string
   TestValue(&d)
   fmt.Printf("c=%v, d=%v\n",c,d)
}

結構體反射

type Users struct {
   Name string  `json:"name"`
   Age int
   Sex string
}

//1. 獲取a的類型
//2. 我要動態改變a裏面存的值
//3. 如果a裏面存儲的是一個結構體,那可以通過反射獲取結構體中的字段信息以及調用結構體裏面的方法
func TestValueStruct(a interface{}) {

   v := reflect.ValueOf(a)
   t := v.Type()
   switch t.Kind()  {
   case reflect.Struct:
      fieldNum := t.NumField()
      fmt.Printf("field num:%d\n", fieldNum)
      for i := 0; i <fieldNum; i++{
         field := t.Field(i)
         vField := v.Field(i)

         fmt.Printf("field[%d] name:%s, json key:%s, val:%v\n",
            i, field.Name, field.Tag.Get("json"), vField.Interface())
      }

   }
}
func main()  {
      var user Users
      user.Name = "xxx"
      user.Age = 100
      user.Sex = "man"
      TestValueStruct(user)
      fmt.Printf("user:%#v\n", user)
}

調用結構體中的方法

type S struct {
   A int
   B string
}

func (s *S) Test() {
   fmt.Printf("this is a test\n")
}

func (s *S) SetA (a int) {
   s.A = a
}

func main() {
   s := S{23,"abc"}
   v := reflect.ValueOf(&s)
   m := v.MethodByName("Test")
   var args1 []reflect.Value
   m.Call(args1)
   setA := v.MethodByName("SetA")
   var args2 []reflect.Value
   args2 = append(args2,reflect.ValueOf(100))
   setA.Call(args2)   #修改結構體中的值
   fmt.Printf("s:%#v\n",s)
}

反射總結以及應用場景

  • 總結:

    • 在運行時動態的獲取一個變量的類型信息(typeOf)和值信息(valueOf)
  • 應用場景
    • 各種數據庫的ORM
      • 配置文件相關的庫,比如yaml,ini等
      • 序列化和反序列化,比如json,protoBuf等數據協議

json序列化簡版代碼

package json_reflect

import (
   "fmt"
   "reflect"
)
func Marshals(data interface{}) (jsonStr string) {

   t := reflect.TypeOf(data)
   v := reflect.ValueOf(data)
   switch t.Kind(){
   case reflect.String,reflect.Int,reflect.Int32:
      jsonStr = fmt.Sprintf("\"%v\"", data)
   case reflect.Struct:
      numField := t.NumField()
      for i := 0; i < numField; i++ {
         //類型信息
         name := t.Field(i).Name
         tag := t.Field(i).Tag.Get("json")
         if len(tag) > 0 {
            name = tag
         }
         //值信息
         vField := v.Field(i)
         vFieldValue := vField.Interface()
         //拼接json
         if t.Field(i).Type.Kind()  == reflect.String {
            jsonStr += fmt.Sprintf("\"%s\":\"%v\"", name, vFieldValue)
         } else {
            jsonStr += fmt.Sprintf("\"%s\":%v", name, vFieldValue)
         }

         if i != numField - 1 {
            jsonStr += ","
         }
      }

      jsonStr = "{" +jsonStr + "}"
   }
   return
}

測試代碼

package main

import (
   "fmt"
   "oldBoy/day9/json_reflect"
)

type User struct {
   Name string `json:"name"`
   Age  int    `json:"age"`
   Sex  string `json:"sex"`
}

func main() {
   var a string = "hello abc"
   jsonStr := json_reflect.Marshals(a)
   fmt.Printf(jsonStr)

   var user User
   user.Name = "aaa"
   user.Age = 10
   user.Sex = "male"

   jsonStr = json_reflect.Marshals(user)
   fmt.Printf(jsonStr)
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章