这是我参与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"))
}
总结
反射机制提高了语言的灵活性, 利用反射机制我们可以写出更加强大的框架, 但是, 如果适用滥用, 就会造成我们的代码可读性非常差. 因此在项目中使用反射机制要节制, 适可而止!!!