一篇文章教会你Go语言基础之结构体反射

开发 后端
本篇从主要讲述Go反射结构体的相关知识:反射在结构体中的应用,如何单独反射结构体字段信息,ValueOf其他操作,如何放射结构体绑定的方法。

[[358777]]

 前言

Hey,大家好呀,我是码农,星期八。

反射在结构体中的应用,才是最广泛的!毕竟在Go中,是用结构体代替对象的!

所以最多的,最麻烦的,也是反射结构体,也是最灵活的!

反射在结构体的应用

上次讲的,只是在普通变量中的应用,相对来说,使用的场景不是太多。

但是反射在结构体中的应用,基本会贯穿整个Go语言基础。

示例代码

结构体

  1. type Student struct { 
  2.     Name   string   `json:"name" describe:"姓名"
  3.     Age    int      `json:"age" describe:"年龄"
  4.     Gender bool     `json:"gender" describe:"性别"
  5.     Hobby  []string `json:"hobby" describe:"爱好"

main

  1. func main() { 
  2.     //实例化结构体 
  3.     var s1 = Student{ 
  4.         Name:   "张三", 
  5.         Age:    18, 
  6.         Gender: true, 
  7.         Hobby:  []string{"吃", "喝", "pia", "玩"}, 
  8.     var t = reflect.TypeOf(s1) 
  9.     fmt.Println(t.Name())     //Student 
  10.     fmt.Println(t.Kind())     //struct 
  11.     fmt.Println(t.NumField()) //结果:4,表示多少个字段 
  12.     for i := 0; i < t.NumField(); i++ { 
  13.         field := t.Field(i)//每个结构体对象 
  14.         /* 
  15.             {Name  string json:"name" describe:"姓名" 0 [0] false
  16.             {Age  int json:"age" describe:"年龄" 16 [1] false
  17.             {Gender  bool json:"gender" describe:"性别" 24 [2] false
  18.             {Hobby  []string json:"hobby" describe:"爱好" 32 [3] false
  19.         */ 
  20.         //fmt.Println(field) 
  21.         fmt.Println("------"
  22.         fmt.Printf("field.Name:%v\n",field.Name
  23.         fmt.Printf("field.Index:%v\n",field.Index
  24.         fmt.Printf("field.Type:%v\n",field.Type) 
  25.         fmt.Printf("field.Tag:%v\n",field.Tag.Get("describe")) 
  26.  
  27.     } 

执行结果


单独反射指定字段信息

main代码

  1. func main() { 
  2.     //实例化结构体 
  3.     var s1 = Student{ 
  4.         Name:   "张三", 
  5.         Age:    18, 
  6.         Gender: true, 
  7.         Hobby:  []string{"吃", "喝", "pia", "玩"}, 
  8.     var t = reflect.TypeOf(s1) 
  9.     genderField, ok := t.FieldByName("Gender"
  10.     if ok { 
  11.         fmt.Println(genderField.Name)                //Gender 
  12.         fmt.Println(genderField.Index)               //[2] 
  13.         fmt.Println(genderField.Type)                //bool 
  14.         fmt.Println(genderField.Tag.Get("describe")) //性别 
  15.     } 

ValueOf

上述的代码只能用的是TypeOf,只能返回类型等信息,相对来说不是太智能,ValueOf可以获取值,同样也能获取类型,相对来说比TypeOf好一点。

示例代码

main

  1. func main() { 
  2.     //实例化结构体 
  3.     var s1 = Student{ 
  4.         Name:   "张三", 
  5.         Age:    18, 
  6.         Gender: true, 
  7.         Hobby:  []string{"吃", "喝", "pia", "玩"}, 
  8.     var v = reflect.ValueOf(s1) 
  9.     for i := 0; i < v.NumField(); i++ { 
  10.         field :=v.Field(i) 
  11.         fmt.Println("------"
  12.         fmt.Printf("Kind:%v\n",field.Kind()) 
  13.         fmt.Printf("值:%v\n",field.Interface()) 
  14.     } 

执行结果

 

反射方法

上述我们反射的都是值,有没有反射是否可以反射函数,并且调用函数呢??

结构体和绑定函数代码

  1. type Student struct { 
  2.     Name   string   `json:"name" describe:"姓名"
  3.     Age    int      `json:"age" describe:"年龄"
  4.     Gender bool     `json:"gender" describe:"性别"
  5.     Hobby  []string `json:"hobby" describe:"爱好"
  6.  
  7. //无参方法 
  8. func (this Student) Say() { 
  9.     fmt.Printf("我是%v,我的年龄是%v,我的性别是%v,我的爱好是%v\n", this.Name, this.Age, this.Gender, this.Hobby) 
  10. //有参数方法 
  11. func (this Student) Jump(distance int) { 
  12.     fmt.Printf("我是%v,我跳远跳了%v米\n", this.Name, distance) 

main

  1. func main() { 
  2.     //实例化结构体 
  3.     var s1 = Student{ 
  4.         Name:   "张三", 
  5.         Age:    18, 
  6.         Gender: true, 
  7.         Hobby:  []string{"吃", "喝", "pia", "玩"}, 
  8.     var t = reflect.TypeOf(s1) 
  9.     var v = reflect.ValueOf(s1) 
  10.     fmt.Println(v.NumMethod(),v.NumField()) 
  11.     for i := 0; i < v.NumMethod(); i++ { 
  12.         method := v.Method(i) 
  13.         fmt.Println("--------"
  14.         fmt.Println(method)//0x48c4e0 函数地址 
  15.         fmt.Println(method.Type())//func(int) 函数类型,形参和返回值 
  16.         fmt.Println(t.Method(i).Name)//Jump,函数名,注意,由t来调用的 
  17.     } 

执行结果

 

反射调用函数

  1. func main() { 
  2.     //实例化结构体 
  3.     var s1 = Student{ 
  4.         Name:   "张三", 
  5.         Age:    18, 
  6.         Gender: true, 
  7.         Hobby:  []string{"吃", "喝", "pia", "玩"}, 
  8.     var v = reflect.ValueOf(s1) 
  9.  
  10.     //通过反射调用函数 
  11.     //调用Jump函数 
  12.     //反射调用函数必须传一个参数,不管有没有形参都要传 
  13.     //var args = []reflect.Value{} 
  14.     //v.MethodByName("Say").Call(args) 
  15.  
  16.     //如果需要传参数 
  17.     //参数需要用reflect.ValueOf(1) 强转一下 
  18.  
  19.     var args = []reflect.Value{reflect.ValueOf(2)} 
  20.     v.MethodByName("Jump").Call(args) 

注:注意第14行和20行代码区别,如果要传参数,参考第20行代码。

执行结果


反射注意事项

在平常开发中,尽量慎用反射,原因如下。

  • 反射性能可能会比较低,毕竟是反正走的,一般比正向操作慢一两个级别。
  • 反射越多,代码越烂,TypeOf和ValueOf都有Kind,很多情况是TypeOf和ValueOf混用的,所以对于基础不好的,极不友好。
  • 在Go中,是没有try的,如果反射没有处理好异常,程序会直接崩溃,可能在意想不到的地方。

总结

上述我们主要讲述了Go反射结构体的相关知识,包括有

  • 反射在结构体中的应用
  • 如何单独反射结构体字段信息
  • ValueOf其他操作
  • 如何放射结构体绑定的方法

到此为止反射就讲完了,一定要多尝试,多敲敲代码,反射的用法还有很多。

 

责任编辑:姜华 来源: Go语言进阶学习
相关推荐

2020-12-16 08:07:28

语言基础反射

2021-05-29 10:20:54

GoModules语言

2021-09-15 10:00:33

Go语言Modules

2020-10-22 08:33:22

Go语言

2020-11-11 10:52:54

Go语言C语言

2020-11-05 09:58:16

Go语言Map

2020-12-23 08:39:11

Go语言基础技术

2022-02-16 10:03:06

对象接口代码

2020-11-13 08:14:28

JavaScript

2019-10-17 19:15:22

jQueryJavaScript前端

2020-12-07 05:59:02

语言Go接口

2021-01-13 08:40:04

Go语言文件操作

2021-10-30 10:43:04

语言Go函数

2021-11-03 10:02:07

Go基础函数

2021-02-20 10:06:14

语言文件操作

2022-04-27 10:01:43

切片Go封装

2021-10-09 07:10:31

Go语言基础

2020-10-25 07:33:13

Go语言

2020-12-09 09:59:32

Go语言技术

2020-10-23 08:38:19

Go语言
点赞
收藏

51CTO技术栈公众号