目录
1. reflect 包1.1 获取变量类型1.2 断言处理类型转换2. ValueOf2.1 获取变量值2.2 类型转换3. Value.Set3.1 设置变量值3.2 示例4. 结构体反射4.1 查看结构体字段数量和方法数量4.2 获取结构体属性4.3 更改属性值4.4 Tag原信息处理5. 函数反射6. 方法反射6.1 使用 MethodByName 名称调用方法6.2 使用 method 索引调用方法反射指的是运行时动态的获取变量的相关信息
1. reflect 包
类型是变量,类别是常量
reflect.TypeOf,获取变量的类型,返回reflect.Type类型
reflect.ValueOf,获取变量的值,返回reflect.Value类型
reflect.Value.Kind,获取变量的类别,返回一个常量
reflect.Value.Interface(),转换成interface{}类型
1.1 获取变量类型
package main import ( "fmt" "reflect" ) func Test(i interface{}) { //反射数据类型 t := reflect.TypeOf(i) fmt.Println("类型是", t) //反射数据值 v := reflect.ValueOf(i) fmt.Println("值是", v) } func main() { a := "hello" Test(a) }
输出结果如下
类型是 string
值是 hello
package main import ( "fmt" "reflect" ) type Student struct { Name string Age int Score float32 } func Test(i interface{}) { //反射获取类型 t := reflect.TypeOf(i) fmt.Println("类型是", t) //反射获取值 v := reflect.ValueOf(i) //判断值的类别 c := v.Kind() fmt.Println("类别是", c) } func main() { var stu Student = Student{ Name: "张三", Age: 18, Score: 80, } Test(stu) fmt.Println("-------------") var num int = 10 Test(num) }
输出结果如下
类型是 main.Student
类别是 struct
-------------
类型是 int
类别是 int
1.2 断言处理类型转换
package main import ( "fmt" "reflect" ) type Student struct { Name string Age int Score float32 } func Test(i interface{}) { t := reflect.TypeOf(i) fmt.Println("类型是", t) //类别 v := reflect.ValueOf(i) c := v.Kind() fmt.Println("类别是", c) fmt.Printf("c的类型是%T\n", c) fmt.Printf("v的类型是%T\n", v) //转换成接口 iv := v.Interface() fmt.Printf("iv的类型%T\n", iv) //断言处理 stu_iv, err := iv.(Student) if err { fmt.Printf("stu_iv的类型%T\n", stu_iv) } } func main() { var stu Student = Student{ Name: "张三", Age: 18, Score: 80, } Test(stu) }
输出结果如下
类型是 main.Student
类别是 struct
c的类型是reflect.Kind
v的类型是reflect.Value
iv的类型main.Student
stu_iv的类型main.Student
2. ValueOf
2.1 获取变量值
reflect.valueof(x).Float()
reflect.valueof(x).Int()
reflect.valueof(x).String()
reflect.Valueof(x).Bool()
2.2 类型转换
package main import ( "fmt" "reflect" ) func Test(i interface{}) { v := reflect.ValueOf(i) fmt.Printf("v的类型是%T\n", v) //转换成指定类型 t := v.Int() fmt.Printf("t的类型是%T\n", t) } func main() { //类型不同的话会报错 var num int = 100 Test(num) }
输出结果如下
v的类型是reflect.Value
t的类型是int64
3. Value.Set
3.1 设置变量值
reflect.Value.SetFloat(),设置浮点数
reflect.value.SetInt(),设置整数
reflect.Value.SetString(),设置字符串
3.2 示例
package main import ( "fmt" "reflect" ) func Test(i interface{}) { v := reflect.ValueOf(i) //更新值需要value的地址,否则会保存,Elem()表示指针* v.Elem().SetInt(100) result := v.Elem().Int() fmt.Printf("result类型为 %T, 值为 %d\n", result, result) } func main() { var num int = 10 Test(&num) }
输出结果如下
result类型为 int64, 值为 100
4. 结构体反射
反射出结构体的属性和方法数量
方法名需大写,需要被跨包调用识别
4.1 查看结构体字段数量和方法数量
package main import ( "fmt" "reflect" ) //结构体 type Student struct { Name string Age int Score float32 } //结构体方法 func (s Student) Run() { fmt.Println("Running") } func (s Student) Sleep() { fmt.Println("Sleeping") } //使用反射查看结构体字段数量和方法数量 func Test(i interface{}) { v := reflect.ValueOf(i) //类别判断 if v.Kind() != reflect.Struct { fmt.Println("不是结构体") return } //获取结构体中字段数量 stu_num := v.NumField() fmt.Println("字段数量: ", stu_num) //获取结构体中方法数量 stu_meth := v.NumMethod() fmt.Println("方法数量: ", stu_meth) } func main() { var stu Student = Student{ Name: "张三", Age: 18, Score: 88, } Test(stu) }
输出结果如下
字段数量: 3
方法数量: 2
4.2 获取结构体属性
package main import ( "fmt" "reflect" ) type Student struct { Name string Age int Score float32 } func Test(i interface{}) { v := reflect.ValueOf(i) //获取结构体中每个属性 for i := 0; i < v.NumField(); i++ { //输出属性值 fmt.Printf("%d %v\n", i, v.Field(i)) //输出属性值的类型 fmt.Printf("%d %v\n", i, v.Field(i).Kind()) } } func main() { var stu Student = Student{ Name: "张三", Age: 18, Score: 88, } Test(stu) }
输出结果如下
0 张三
0 string
1 18
1 int
2 88
2 float32
4.3 更改属性值
package main import ( "fmt" "reflect" ) type Student struct { Name string Age int Score float32 } func Test(i interface{}, name string) { v := reflect.ValueOf(i) vk := v.Kind() //判断是都为指针并指向结构体类型 if vk != reflect.Ptr && v.Elem().Kind() == reflect.Struct { fmt.Println("expect struct") return } //更改属性值 v.Elem().Field(0).SetString(name) //获取结构体中每个属性 for i := 0; i < v.Elem().NumField(); i++ { //输出属性值 fmt.Printf("%d %v\n", i, v.Elem().Field(i)) //输出属性值的类型 fmt.Printf("%d %v\n", i, v.Elem().Field(i).Kind()) } } func main() { var stu Student = Student{ Name: "张三", Age: 18, Score: 88, } Test(&stu, "李四") }
输出结果如下
0 李四
0 string
1 18
1 int
2 88
2 float32
4.4 Tag原信息处理
package main import ( "encoding/json" "fmt" "reflect" ) type Student struct { Name string `json:"stu_name"` Age int Score float32 } func Test(i interface{}, name string) { v := reflect.ValueOf(i) vk := v.Kind() //判断是都为指针并指向结构体类型 if vk != reflect.Ptr && v.Elem().Kind() == reflect.Struct { fmt.Println("expect struct") return } //更改属性值 v.Elem().Field(0).SetString(name) //获取结构体中每个属性 for i := 0; i < v.Elem().NumField(); i++ { //输出属性值 fmt.Printf("%d %v\n", i, v.Elem().Field(i)) //输出属性值的类型 fmt.Printf("%d %v\n", i, v.Elem().Field(i).Kind()) } } func main() { var stu Student = Student{ Name: "张三", Age: 18, Score: 88, } Test(&stu, "李四") fmt.Println("----------------json原信息----------------") result, _ := json.Marshal(stu) fmt.Println("json原信息: ", string(result)) //反射获取类型 st := reflect.TypeOf(stu) s := st.Field(0) fmt.Printf("Name原信息名称: %s\n", s.Tag.Get("json")) }
输出结果如下
0 李四
0 string
1 18
1 int
2 88
2 float32
----------------json原信息----------------
json原信息: {"stu_name":"李四","Age":18,"Score":88}
Name原信息名称: stu_name
5. 函数反射
Go 中函数是可以赋值给变量的
示例:
既然函数可以像普通的类型变量一样,那么在反射机制中就和不同的变量是一样的,在反射中函数和方法的类型(Type)都是reflect.Func
,如果要调用函数,通过Value
的Call()
方法
package main import ( "fmt" "reflect" ) func hello() { fmt.Println("hello world") } func main() { //反射使用函数 v := reflect.ValueOf(hello) //类型判断是否属于reflect.func类型 if v.Kind() == reflect.Func { fmt.Println("函数") } //反射调用函数 v.Call(nil) //Call中需要传入的是切片 }
输出结果如下
函数
hello world
package main import ( "fmt" "reflect" "strconv" ) //反射调用传参和返回值函数 func Test(i int) string { return strconv.Itoa(i) } func main() { v := reflect.ValueOf(Test) //定义参数切片 params := make([]reflect.Value, 1) //切片元素赋值 params[0] = reflect.ValueOf(20) //反射调函数 result := v.Call(params) fmt.Printf("result的类型是 %T\n", result) //[]reflect.Value切片转换string s := result[0].Interface().(string) fmt.Printf("s的类型是 %T ,值为 %s\n", s, s) }
输出结果如下
result的类型是 []reflect.Value
s的类型是 string ,值为 20
6. 方法反射
反射中方法的调用,函数和方法可以说其实本质上是相同的,只不过方法与一个“对象”进行了“绑定”,方法是“对象”的一种行为,这种行为是对于这个“对象”的一系列操作,例如修改“对象”的某个属性
6.1 使用 MethodByName 名称调用方法
package main import ( "fmt" "reflect" "strconv" ) //反射方法 type Student struct { Name string Age int } //结构体方法 func (s *Student) SetName(name string) { s.Name = name } func (s *Student) SetAge(age int) { s.Age = age } func (s *Student) String() string { return fmt.Sprintf("%p", s) + ",Name:" + s.Name + ",Age:" + strconv.Itoa(s.Age) } func main() { //实例化 stu := &Student{"张三", 19} //反射获取值:指针方式 stuV := reflect.ValueOf(&stu).Elem() fmt.Println("修改前: ", stuV.MethodByName("String").Call(nil)[0]) //修改值 params := make([]reflect.Value, 1) //定义切片 params[0] = reflect.ValueOf("李四") stuV.MethodByName("SetName").Call(params) params[0] = reflect.ValueOf(20) stuV.MethodByName("SetAge").Call(params) fmt.Println("修改后: ", stuV.MethodByName("String").Call(nil)[0]) }
输出结果如下
修改前: 0xc000004078,Name:张三,Age:19
修改后: 0xc000004078,Name:李四,Age:20
6.2 使用 method 索引调用方法
package main import ( "fmt" "reflect" "strconv" ) //反射方法 type Student struct { Name string Age int } //结构体方法 func (s *Student) B(name string) { s.Name = name } func (s *Student) A(age int) { s.Age = age } func (s *Student) C() string { return fmt.Sprintf("%p", s) + ",Name:" + s.Name + ",Age:" + strconv.Itoa(s.Age) } func main() { //实例化 stu := &Student{"张三", 19} //反射获取值:指针方式 stuV := reflect.ValueOf(&stu).Elem() //索引调用方法 fmt.Println("修改前: ", stuV.Method(2).Call(nil)[0]) params := make([]reflect.Value, 1) params[0] = reflect.ValueOf("李四") stuV.Method(1).Call(params) params[0] = reflect.ValueOf(20) stuV.Method(0).Call(params) fmt.Println("修改后: ", stuV.Method(2).Call(nil)[0]) //调用索引大小取决于方法名称的ASCII大小进行排序 }
输出结果如下
修改前: 0xc000004078,Name:张三,Age:19
修改后: 0xc000004078,Name:李四,Age:20
到此这篇关于Go语言学习之反射的用法详解的文章就介绍到这了,更多相关Go语言反射内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
上一篇:Go语言学习之文件操作方法详解
X 关闭
X 关闭
- 15G资费不大降!三大运营商谁提供的5G网速最快?中国信通院给出答案
- 2联想拯救者Y70发布最新预告:售价2970元起 迄今最便宜的骁龙8+旗舰
- 3亚马逊开始大规模推广掌纹支付技术 顾客可使用“挥手付”结账
- 4现代和起亚上半年出口20万辆新能源汽车同比增长30.6%
- 5如何让居民5分钟使用到各种设施?沙特“线性城市”来了
- 6AMD实现连续8个季度的增长 季度营收首次突破60亿美元利润更是翻倍
- 7转转集团发布2022年二季度手机行情报告:二手市场“飘香”
- 8充电宝100Wh等于多少毫安?铁路旅客禁止、限制携带和托运物品目录
- 9好消息!京东与腾讯续签三年战略合作协议 加强技术创新与供应链服务
- 10名创优品拟通过香港IPO全球发售4100万股 全球发售所得款项有什么用处?