反射

变量介绍

  • 变量的内在机制
    • 类型信息,这部分是元信息,是预先定义好的
    • 值类型,这部分是在程序运行过程中动态改变的

反射介绍

  • 反射与空接口
    • 空接口可以存储任何类型的变量
    • 在程序运行时动态获取变量的类型信息和值信息,就叫反射
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)
}