golang反射reflect

1 reflect包

reflect包实现了运行时反射,允许程序操作任意类型的对象。典型用法是用静态类型interface{}保存一个值,通过调用TypeOf获取其动态类型信息,该函数返回一个Type类型值。调用ValueOf函数返回一个Value类型值,该值代表运行时的数据。Zero接受一个Type类型参数并返回一个代表该类型零值的Value类型值。

①对基本数据类型进行反射:

package main

import (
   "fmt"
   "reflect"
)

func reflectNum(arg interface{}) {
   fmt.Println("value:", reflect.ValueOf(arg))
   fmt.Println("type:", reflect.TypeOf(arg))
}

func main() {
   var num float64 = 1.2334
   reflectNum(num)
}

控制台输出:

value: 1.2334
type: float64

②对结构体类型进行反射:

package main

import (
   "fmt"
   "reflect"
)

type User struct {
   Id   int
   Name string
   Age  int
}

func (u User) Call() {
   fmt.Println("User is called ..")
   fmt.Printf("%v\n", u)
}

func DoFieldAndMethod(i interface{}) {
   //获取input的type
   inputType := reflect.TypeOf(i)
   fmt.Println("inputType is :", inputType.Name()) //Type类的Name()方法可以直接返回当前类型的名称

   //获取input的value
   inputValue := reflect.ValueOf(i)
   fmt.Println("inputValue is :", inputValue)

   //通过Type类和Value类对结构体的字段进行访问
   for i := 0; i < inputType.NumField(); i++ { //Type类的NumField()方法返回当前类型属性的个数
      field := inputType.Field(i)              //Type类的Field(i int)方法返回当前类的第i个字段
      value := inputValue.Field(i).Interface() //通过Value类的Field()拿到当前类的第i个字段,再通过Interface()返回v当前持有的值(表示为/保管在interface{}类型)

      fmt.Printf("%s : %v = %v\n", field.Name, field.Type, value)
   }

   //通过type获取里面的方法
   for i := 0; i < inputType.NumMethod(); i++ { //Type类的NumMethod()方法返回当前类型方法的个数
      m := inputType.Method(i)
      fmt.Printf("%s : %v\n", m.Name, m.Type)
   }
}

func main() {
   user := User{1, "liam", 23}
   //fmt.Println(reflect.ValueOf(user).Field(1).Interface())
   DoFieldAndMethod(user)
}

控制台输出:

inputType is : User
inputValue is : {1 liam 23}
Id : int = 1
Name : string = liam
Age : int = 23
Call : func(main.User)

2 反射解析结构体标签Tag

可以在结构体字段后用“ `` ”来对字段添加说明标签:

type resume struct {
	Name   string `info:"name" doc:"我的名字"`
	Gender rune   `info:"gender"`
}

可以通过反射来访问结构体字段的Tag:

package main

import (
   "fmt"
   "reflect"
)

type resume struct {
   Name   string `info:"name" doc:"我的名字"`
   Gender rune   `info:"gender"`
}

func findTag(str interface{}) {
   t := reflect.TypeOf(str).Elem()

   for i := 0; i < t.NumField(); i++ {
      tagInfo := t.Field(i).Tag.Get("info")
      tagDoc := t.Field(i).Tag.Get("doc")
      fmt.Println("info:", tagInfo, "doc:", tagDoc)
   }
}

func main() {
   var re resume
   findTag(&re)
}

控制台输出:

info: name doc: 我的名字
info: gender doc: 

2.1 结构体标签在json中的应用

可以通过encoding/json包来将结构体和json格式相互转换:

package main

import (
   "encoding/json"
   "fmt"
)

type Movie struct {
   Title  string   `json:"title"`
   Year   int      `json:"year"`
   Price  int      `json:"rmb"`
   Actors []string `json:"actors"`
}

func main() {
   movie := Movie{
      Title:  "CatchMeIfYouCan",
      Year:   2002,
      Price:  20,
      Actors: []string{"Leonardo", "TomHanks"},
   }
   //编码过程:结构体--->json
   jsonStr, err := json.Marshal(movie)
   if err != nil {
      fmt.Println("json marshal err:", err)
      return
   }
   fmt.Printf("%s\n", jsonStr)

   //解码过程:json--->结构体
   myMovie := Movie{}
   err = json.Unmarshal(jsonStr, &myMovie)
   if err != nil {
      fmt.Println("json unmarshal err:", err)
      return
   }
   fmt.Printf("%v\n", myMovie)
}

控制台输出:

{"title":"CatchMeIfYouCan","year":2002,"rmb":20,"actors":["Leonardo","TomHanks"]}
{CatchMeIfYouCan 2002 20 [Leonardo TomHanks]}
posted @ 2022-08-21 20:46  雪碧锅仔饭  阅读(190)  评论(0)    收藏  举报