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

开发 后端
Hey,大家好呀,我是码农,星期八!,我们以前学的呀,都属于正向定义变量,正向开发!但是有没有什么办法能反着来呢?根据变量获取类型等操作。

 [[357962]]

前言

Hey,大家好呀,我是码农,星期八!,我们以前学的呀,都属于正向定义变量,正向开发!

但是有没有什么办法能反着来呢?根据变量获取类型等操作。

一起来看看Go的反射吧!!!

什么是反射

反射,嗯...,就是反着的意思呗,就是把东西反过来。

比如这样的一个很简单的代码。

  1. var a int = 3 
  2. fmt.Println(a) 

我们当然知道a变量是int类型,但是反过来想,程序是怎么知道a是int类型呢???

这时候,就需要用到反射了。

示例代码

  1. v := reflect.TypeOf(a) 
  2. fmt.Println(v) 

两次代码综合一块执行结果

第二次的第2行代码,成功的将变量a还原出了int类型。

什么???你为我有什么用???,嗯。。。实话实说,用的不是太多,但是必须要会的。

反射(reflect包)

在Go中,任何变量,都有具体类型和具体值,就像var a int = 3,具体类型就是int,具体值就是3。

所以,变量的具体类型归属在reflect.Type,变量的具体值归属在reflect.Value。

并且Go的提供了

  • reflect.TypeOf获取具体类型。
  • reflect.ValueOf获取具体值。

TypeOf

TypeOf方法可以获取变量的具体类型。

有一个这样的需求,定义一个函数,可以接收任意类型数据,通过反射打印变量类型。

示例代码

函数

  1. func reflectType(x interface{}) { 
  2.     v := reflect.TypeOf(x) 
  3.     fmt.Printf("你传入的变量类型是:%v\n",v) 

main

  1. func main() { 
  2.     var a int = 666 
  3.     var b float64 = 3.14 
  4.     var c string = "hello world" 
  5.     var d [3]int = [3]int{1,2,6} 
  6.     var e []int = []int{1,2,6,88} 
  7.     var f map[string]interface{} = map[string]interface{}{ 
  8.         "Name":"张三", 
  9.         "Age":18, 
  10.     reflectType(a) 
  11.     reflectType(b) 
  12.     reflectType(c) 
  13.     reflectType(d) 
  14.     reflectType(e) 
  15.     reflectType(f) 

执行结果

通过reflect.TypeOf方法,完美解决上述需求。

TypeOf 的Name和Kind

这个是啥意思呢??这个在结构体中比较好体现。

简答来说就是TypeOf返回的太笼统了,还有更加细化的类型,通过这俩属性获取。

示例代码

函数

  1. func reflectType(x interface{}) { 
  2. v := reflect.TypeOf(x) 
  3. fmt.Printf("你传入的变量类型是:%v | Name:%v | Kind:%v\n", v, v.Name(), v.Kind()) 

结构体

  1. type Student struct { 
  2.     Name string 
  3.     Age int 

main

  1. func main() { 
  2.     var a int 
  3.     var b *int 
  4.     var c []int 
  5.     var d map[string]interface{} 
  6.     var e Student 
  7.     reflectType(a) 
  8.     reflectType(b) 
  9.     reflectType(c) 
  10.     reflectType(d) 
  11.     reflectType(e) 

执行结果

总结

经过对比,会发现几个特殊问题。

如果变量是指针类型,Name为空,Kind是ptr。

如果变量是引用类型(切片和map)类型,Name为空,只有Kind。

如果变量是结构体,Name是结构体名,Kind是struct。

ValueOf

TypeOf只能反过来获取变量的具体类型,但是并不能获取具体值,这就有点不太厚道了。

所以ValueOf就来解决这个问题了,但是ValueOf牛叉的是,它里面还包括了变量类型。

注:ValueOf和TypeOf的Kind属性返回内容是一摸一样的。

需求:定义一个函数,可以接收任意类型,通过反射得出变量类型和变量值。

函数

  1. func reflectType(x interface{}) { 
  2.     v := reflect.ValueOf(x) 
  3.     k := v.Kind() 
  4.     switch k { 
  5.     case reflect.Int
  6.         fmt.Printf("我是Int类型,我的值是%v\n",v.Int()) 
  7.     case reflect.Slice: 
  8.         fmt.Printf("我是切片类型,我的值是%v\n",v.Slice(1,2)) 
  9.     case reflect.Map: 
  10.         fmt.Printf("我是切片类型,我的值是%v\n",v.MapKeys()) 
  11.     //case :可以继续case下去 
  12.   } 

main

  1. func main() { 
  2.   var a int = 1 
  3.   var c []int = []int{1, 5, 7, 19} 
  4.   var d map[string]interface{} = map[string]interface{}{ 
  5.     "Name""你好", 
  6.     "Age":  18, 
  7.   } 
  8.   var e Student 
  9.   reflectType(a) 
  10.  
  11.   reflectType(c) 
  12.   reflectType(d) 
  13.   reflectType(e) 

执行结果

通过反射设置值

反射还有一个用途,就是动态的修改变量值,可能你暂时体会不到,但是语法还是要学的。

通过反射设置值,需要用到Elem方法,并且传入的必须是指针。

示例代码

函数

  1. func reflectSetValue(x interface{}) { 
  2.   v := reflect.ValueOf(x) 
  3.   //kind也必须是Elem调用 
  4.   var k = v.Elem().Kind() 
  5.   switch k { 
  6.   case reflect.Int
  7.     //反射修改必须通过Elem 
  8.     v.Elem().SetInt(200) 
  9.   } 

main

  1. func main() { 
  2.   var a int = 10 
  3.   fmt.Printf("a的值:%v\n", a) 
  4.   //反射修改值传入的必须是地址 
  5.   reflectSetValue(&a) 
  6.   fmt.Printf("a的值:%v\n", a) 

执行结果

总结

上述我们学习了Go基础反射的TypeOf,TypeOf的Name和Kind,ValueOf,通过反射设置值。

其中Kind在Type和ValueOf中都有,通常情况下TypeOf和ValueOf一起使用效果更佳!

反射这一块,可能不是那么好理解,一定要多多下功夫!坚持!!

如果在操作过程中有任何问题,记得下面留言,我们看到会第一时间解决问题。我是码农星期八,如果觉得还不错,记得动手点赞一下哈。感谢你的观看。

本文转载自微信公众号「Go语言进阶学习」,可以通过以下二维码关注。转载本文请联系Go语言进阶学习公众号。

 

责任编辑:武晓燕 来源: Go语言进阶学习
相关推荐

2020-12-20 09:59:13

Go语言基础技术

2021-09-15 10:00:33

Go语言Modules

2021-05-29 10:20:54

GoModules语言

2019-10-17 19:15:22

jQueryJavaScript前端

2020-11-05 09:58:16

Go语言Map

2020-12-23 08:39:11

Go语言基础技术

2022-02-16 10:03:06

对象接口代码

2020-10-22 08:33:22

Go语言

2020-11-11 10:52:54

Go语言C语言

2021-02-19 19:35:53

SVG 形状元素

2023-06-21 00:10:17

JSONWeb服务器JavaScript

2020-11-13 08:14:28

JavaScript

2020-10-23 08:38:19

Go语言

2021-02-20 10:06:14

语言文件操作

2020-12-09 09:59:32

Go语言技术

2020-12-30 09:04:32

Go语言TCPUDP

2020-12-27 10:15:44

Go语言channel管道

2020-10-25 07:33:13

Go语言

2022-04-27 10:01:43

切片Go封装

2021-10-09 07:10:31

Go语言基础
点赞
收藏

51CTO技术栈公众号