参考链接:Go 语言反射的实现原理 | Go 语言设计与实现
https://juejin.cn/post/6844904177009688589
在程序运行期间对程序本身进行访问和修改的能力,程序在编译时,变量转换为内存地址,变量名不会写入到可执行部分,程序无法获取自身信息
支持反射语言可以在编译期间的变量的反射信息,如字段名称、类型信息、结构体信息整合到可执行文件当中,并提供接口供访问,这样在程序运行期间可以获取反射信息并可以修改。
反射中两对重要的函数和类型
函数:
类型:reflect.Type reflect.Value这是两个接口
通过TypeOf,ValueOf转换为Type,Value接口,之后就可以进行复杂操作
三大法则:
翻译一下,就是:
法则1:将接口类型变量 转换为“反射类型对象”;
因为TypeOf,ValueOf的形参类型是interface{},所以实参任何值都会隐式转换为接口。
法则2:将"反射类型对象"转换为接口;
其中调用Interface()方法,并且只能返回reflect.Value这个类型。
- package main
-
- import (
- "fmt"
- "reflect"
- )
-
- func main() {
- var author interface{}
- author = "张三"
- //type类型,value
- //法则1:从接口到反射对象
- t := reflect.TypeOf(author)
- v := reflect.ValueOf(author)
- fmt.Printf("接口到反射对象:t:%v typeof(t):%T\n", t, t)
- fmt.Printf("接口到反射对象:v:%v typeof(v):%T\n", v, v)
-
- //法则2:反射可以将 “反射类型对象”转换为 接口类型变量
- //其中调用Interface()方法,转回
- i := v.Interface()
- fmt.Printf("反射对象到接口 %T %v\n", i, i)
-
- i = "李四"
- fmt.Printf("%p\n", &author)
- fmt.Printf("%p\n", &i)
- }
第三定律:要修改 “反射类型对象” 其类型必须是 可写的;
reflect.ValueOf如果接收变量,则canSet()可写性false
如果canSet()不可写,但仍修改对象,则报错
- package main
-
- import (
- "fmt"
- "reflect"
- )
-
- func main() {
- var name string = "Go编程时光"
- fmt.Println("真实世界里 name 的原始值为:", name)
-
- v1 := reflect.ValueOf(&name)
- v2 := v1.Elem()
-
- v2.SetString("Python编程时光")
- fmt.Println("通过反射对象进行更新后,真实世界里 name 变为:", name)
- }