Go中的reflect

657 阅读2分钟

这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战

reflect

反射机制在运行时动态获取方法和属性, 然后可以对其进行操作

比如: 可以利用反射机制获取结构体的字段信息, 方法信息, 还可以更改字段信息, 调用结构体中的方法

type Person struct {
	name string
}

// 基本数据类型
i := 10
f := 3.14

// 基本的复合类型
a := [3]string {"shaosiming", "dasiming", "tianming"}
s := []int{1, 2, 3}
m := map[string]int {"shaosiming":18, "dasiming":20, "tianming":6}
var c chan int

// 自定义的复合类型
p := Person{"shaosiming"}

TypeOf()

func testType(o interface{})  {
   /*
   返回被检测对象的类型
   func TypeOf(i interface{}) Type
   返回参数Type: 是一个结构体, 里面包含一些类型信息
   */
   t := reflect.TypeOf(o)

   // Name函数返回类型名, Kind()函数返回种类名
   /*
   对于基本数据类型 Name和King函数返回值一样
   对于array, slice, map, chan, Name函数返回空
   对于struct, Name函数返回结构体名, Kind函数返回struct
   */
   fmt.Println(t, t.Name(), t.Kind())
}

/* 输出结果
~~~~~~~~~ TypeOf ~~~~~~~~~
int int int
float64 float64 float64
[3]string  array
[]int  slice
map[string]int  map
chan int  chan
main.Person Person struct
*/

ValueOf()

func testValue(o interface{})  {
   // 返回被检测对象的Value类型
   v := reflect.ValueOf(o)
   
   // 返回参数的值, 类型和种类
   fmt.Println(v, v.Type(), v.Kind())
}

/* 输出结果
~~~~~~~~~ ValueOf ~~~~~~~~~
10 int int
3.14 float64 float64
[shaosiming dasiming tianming] [3]string array
[1 2 3] []int slice
map[dasiming:20 shaosiming:18 tianming:6] map[string]int map
<nil> chan int chan
{shaosiming} main.Person struct
*/

CanAddr CanSet

fmt.Println("~~~~~~~~~ CanAddr CanSet ~~~~~~~~~")
o := 10
fmt.Println("被修改前的值: ", o)
v := reflect.ValueOf(&o).Elem()
// 判断是否可以获取到地址
if v.CanAddr() {
   fmt.Println("可获取地址")
  // 判断是否可修改该地址中的值
   if v.CanSet() {
      fmt.Println("可被修改")
      v.SetInt(100)
   } else {
      fmt.Println("不可被修改")
   }
} else {
   fmt.Println("不可获取地址")
}
fmt.Println("被修改后的值: ", o)

reflect struct

// 定义结构体
type Student struct {
   name string `json:"json_name" ini:"ini_name"`
   age int       `json:"json_age" ini:"ini_age"`
}

// 结构体的方法
func (s Student) PrintName() string  {
   fmt.Println(s.name)
   return s.name
}

// 结构体的方法
func (s Student) PrintAge() int {
   fmt.Println(s.age)
   return s.age
}

// 结构体的反射
stu := Student{
  name: "shaosiming",
  age:  18,
}

获取结构体的字段

// 获取字段列表
stuV := reflect.ValueOf(stu)

fmt.Println("~~~~~~~~~ NumField ~~~~~~~~~")
fieldList := stuV.NumField()
fmt.Println("字段数量: ", fieldList)
for i := 0; i < fieldList; i++ {
   field := stuV.Field(i)
   fmt.Println(field, field.Type(), field.Kind())
}

获取结构体的方法

// 获取方法列表
fmt.Println("~~~~~~~~~ NumMethod ~~~~~~~~~")
methodList := stuV.NumMethod()
fmt.Println("方法数量: ", methodList)
for i := 0; i < methodList; i++ {
   method := stuV.Method(i)
   fmt.Println(method.Type(), method.Kind())
}

获取结构体的标签

// 获取标签
stuT := reflect.TypeOf(stu)
fmt.Println(stuT.NumField())
for i := 0; i < stuT.NumField(); i++ {
   t := stuT.Field(i)
   fmt.Println(t.Tag.Get("json"), t.Tag.Get("ini"))
}

总结

反射机制提高了语言的灵活性, 利用反射机制我们可以写出更加强大的框架, 但是, 如果适用滥用, 就会造成我们的代码可读性非常差. 因此在项目中使用反射机制要节制, 适可而止!!!