一篇文章教会你Go语言基础之反射
共 3311字,需浏览 7分钟
·
2020-12-20 16:22
回复“Go语言”即可获赠从入门到进阶共10本电子书
四月南风大麦黄,枣花未落桐叶长。
前言
Hey,大家好呀,我是码农,星期八!,我们以前学的呀,都属于正向定义变量,正向开发!
但是有没有什么办法能反着来呢?根据变量获取类型等操作。
一起来看看Go的反射吧!!!
什么是反射
反射,嗯...,就是反着的意思呗,就是把东西反过来。
比如这样的一个很简单的代码。
var a int = 3
fmt.Println(a)
我们当然知道a
变量是int
类型,但是反过来想,程序是怎么知道a
是int
类型呢???
这时候,就需要用到反射了。
示例代码
v := reflect.TypeOf(a)
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
方法可以获取变量的具体类型。
有一个这样的需求,定义一个函数,可以接收任意类型数据,通过反射打印变量类型。
示例代码
函数
func reflectType(x interface{}) {
v := reflect.TypeOf(x)
fmt.Printf("你传入的变量类型是:%v\n",v)
}
main
func main() {
var a int = 666
var b float64 = 3.14
var c string = "hello world"
var d [3]int = [3]int{1,2,6}
var e []int = []int{1,2,6,88}
var f map[string]interface{} = map[string]interface{}{
"Name":"张三",
"Age":18,
}
reflectType(a)
reflectType(b)
reflectType(c)
reflectType(d)
reflectType(e)
reflectType(f)
}
执行结果
通过reflect.TypeOf
方法,完美解决上述需求。
TypeOf 的Name和Kind
这个是啥意思呢??这个在结构体中比较好体现。
简答来说就是TypeOf
返回的太笼统了,还有更加细化的类型,通过这俩属性获取。
示例代码
函数
func reflectType(x interface{}) {
v := reflect.TypeOf(x)
fmt.Printf("你传入的变量类型是:%v | Name:%v | Kind:%v\n", v, v.Name(), v.Kind())
}
结构体
type Student struct {
Name string
Age int
}
main
func main() {
var a int
var b *int
var c []int
var d map[string]interface{}
var e Student
reflectType(a)
reflectType(b)
reflectType(c)
reflectType(d)
reflectType(e)
}
执行结果
总结
经过对比,会发现几个特殊问题。
如果变量是指针类型,Name
为空,Kind
是ptr
。
如果变量是引用类型(切片和map)类型,Name
为空,只有Kind
。
如果变量是结构体,Name
是结构体名,Kind
是struct
。
ValueOf
TypeOf
只能反过来获取变量的具体类型,但是并不能获取具体值,这就有点不太厚道了。
所以ValueOf
就来解决这个问题了,但是ValueOf
牛叉的是,它里面还包括了变量类型。
注:ValueOf
和TypeOf
的Kind
属性返回内容是一摸一样的。
需求:定义一个函数,可以接收任意类型,通过反射得出变量类型和变量值。
函数
func reflectType(x interface{}) {
v := reflect.ValueOf(x)
k := v.Kind()
switch k {
case reflect.Int:
fmt.Printf("我是Int类型,我的值是%v\n",v.Int())
case reflect.Slice:
fmt.Printf("我是切片类型,我的值是%v\n",v.Slice(1,2))
case reflect.Map:
fmt.Printf("我是切片类型,我的值是%v\n",v.MapKeys())
//case :可以继续case下去
}
}
main
func main() {
var a int = 1
var c []int = []int{1, 5, 7, 19}
var d map[string]interface{} = map[string]interface{}{
"Name": "你好",
"Age": 18,
}
var e Student
reflectType(a)
reflectType(c)
reflectType(d)
reflectType(e)
}
执行结果
通过反射设置值
反射还有一个用途,就是动态的修改变量值,可能你暂时体会不到,但是语法还是要学的。
通过反射设置值,需要用到Elem
方法,并且传入的必须是指针。
示例代码
函数
func reflectSetValue(x interface{}) {
v := reflect.ValueOf(x)
//kind也必须是Elem调用
var k = v.Elem().Kind()
switch k {
case reflect.Int:
//反射修改必须通过Elem
v.Elem().SetInt(200)
}
}
main
func main() {
var a int = 10
fmt.Printf("a的值:%v\n", a)
//反射修改值传入的必须是地址
reflectSetValue(&a)
fmt.Printf("a的值:%v\n", a)
}
执行结果
总结
上述我们学习了Go基础反射的TypeOf
,TypeOf的Name和Kind
,ValueOf
,通过反射设置值
。
其中Kind
在Type
和ValueOf
中都有,通常情况下TypeOf
和ValueOf
一起使用效果更佳!
反射这一块,可能不是那么好理解,一定要多多下功夫!坚持!!
如果在操作过程中有任何问题,记得下面留言,我们看到会第一时间解决问题。我是码农星期八,如果觉得还不错,记得动手点赞一下哈。感谢你的观看。
------------------- End -------------------
往期精彩文章推荐:
欢迎大家点赞,留言,转发,转载,感谢大家的相伴与支持
想加入Go学习群请在后台回复【入群】
万水千山总是情,点个【在看】行不行