深入了解Golang中reflect反射的使用
作者:未来谁可知
这篇文章主要介绍了深入了解Golang中reflect反射的使用,Go语言中的反射是一种机制,可以在运行时动态地获取类型信息和操作对象,以及调用对象的方法和属性等,需要详细了解可以参考下文
1. 介绍
在反射的世界里,我们拥有了获取一个对象的类型,属性及方法的能力。
在 Go 反射的世界里,有两种类型非常重要,是整个反射的核心,在学习 reflect 包的使用时,先得学习下这两种类型:
- reflect.Type
- reflect.Value
2. 方法示例
2.1 通过反射获取对象的键(类型)和值
package main import ( "fmt" "reflect" ) // func reflectNum(arg interface{}) { fmt.Println("type:",reflect.TypeOf(arg)) fmt.Println("value : ",reflect.ValueOf(arg)) } func main() { reflectNum(1.1234) }
type: float64
value : 1.1234
注意,Go 中所有对象都是键+值组成的,含有这种特性的对象都是可以用 Type + Value 进行抽象的,这就是万能对象
2.2 反射对象的类型和属性
package main import ( "fmt" "reflect" ) type User struct { Id int Name string Age int } func (this User) Call() { fmt.Println("user is called ..") fmt.Printf("#{this}\n") } func main() { user := User{1,"Aceld",18} //传入 user 对象 DoFiledAndMethod(user) } //接收万能对象 用反射解析 func DoFiledAndMethod(input interface{}) { //反射获取类的类型 inputType := reflect.TypeOf(input) fmt.Println("inputType is :", inputType.Name() ) // inputType is : User inputValue := reflect.ValueOf(input) fmt.Println("inputValue is :", inputValue) //inputValue is : {1 Aceld 18} //反射获取类的属性 for i := 0; i < inputType.NumField(); i++ { field := inputType.Field(i) value := inputValue.Field(i).Interface() fmt.Printf("%s : %v = %v\n",field.Name,field.Type,value) //Id : int = 1 //Name : string = Aceld //Age : int = 18 } //反射调用方法 for i := 0; i < inputType.NumMethod(); i++ { m := inputType.Method(i) //%s 输出字符串表示(string类型或[]byte) //%v 相应值的默认格式。 fmt.Printf("%s:%v\n",m.Name,m.Type) //Call:func(main.User) } }
3. 反射对Json的操作
3.1 反射与Json属性解析
在结构体属性中 我们可以通过加 tag 以供其他程序的解析与识别
package main import ( "fmt" "reflect" ) type resume struct { // ':'前后不加空格 ` != ' Name string `info:"name" doc:"我的名字" ` Sex string `info:"sex" ` } func findTag(str interface{}) { // Elem returns a type's element type. t := reflect.TypeOf(str).Elem() //遍历接收对象的属性 for i := 0; i < t.NumField(); i++ { taginfo := t.Field(i).Tag.Get("info") tagdoc := t.Field(i).Tag.Get("doc") fmt.Println("info:",taginfo,"doc:",tagdoc) } } func main() { var re resume findTag(&re) } 输出: info: name doc: 我的名字 info: sex doc:
3.2 Json包的序列化与反序列化
go 的 json 工具要想解析 需要你在字段上添加 json tag
package main import ( "encoding/json" "fmt" ) // 全部添加 json 的 tag type Movie struct { Title string `json:"title"` Year int `json:"year"` Price int `json:"rmb"` Actors []string `json:"actors"` } func main() { movie := Movie{"喜剧之王", 2000, 10, []string{"zhouxingchi", "wumengda"}} // 序列化 jsonStr, err := json.Marshal(movie) if err != nil { fmt.Println("json marshal error",err) return } fmt.Printf("jsonStr = %s\n",jsonStr) //反序列化 m := Movie{} err = json.Unmarshal(jsonStr, &m) if err != nil { fmt.Println("json ummarshal error", err) return } fmt.Printf("%v\n",m) }
4. 实战巩固
4.1 需求
项目经常会在启动的时候会加一些环境变量参数,随着启动而触发作用加载到项目中,现如今在。利用os包设置好环境变量,利用反射实现项目启动时运行时加载进环境!
环境变量Key | CONFIG_SERVER_NAME | CONFIG_SERVER_IP | CONFIG_SERVER_URL |
---|
4.2 代码实现
package main import ( "fmt" "os" "reflect" "strings" ) type Config struct { Name string `json:"server-name"` IP string `json:"server-ip"` URL string `json:"server-url"` Timeout string `json:"timeout"` } func readConfig() *Config { // read from xxx.json,省略 config := Config{} // 1. 拿到config的反射类型 typ := reflect.TypeOf(config) // 2. 拿到config的反射值对象 value := reflect.Indirect(reflect.ValueOf(&config)) // 3. 遍历每个字段 for i := 0; i < typ.NumField(); i++ { // 3.1 拿到反射的config的第i个字段 f := typ.Field(i) // 3.2 拿到赋值了json的字段tag if v, ok := f.Tag.Lookup("json"); ok { // 3.3 拼接系统环境变量Key key := fmt.Sprintf("CONFIG_%s", strings.ReplaceAll(strings.ToUpper(v), "-", "_")) // 3.4 从系统中读取环境变量对应的值 if env, exist := os.LookupEnv(key); exist { // 3.5 将值设置到给定名称的字段上 value.FieldByName(f.Name).Set(reflect.ValueOf(env)) } } } return &config } func main() { os.Setenv("CONFIG_SERVER_NAME", "global_server") os.Setenv("CONFIG_SERVER_IP", "10.0.0.1") os.Setenv("CONFIG_SERVER_URL", "geektutu.com") c := readConfig() fmt.Printf("%+v", c) }
到此这篇关于深入了解Golang中reflect反射的使用的文章就介绍到这了,更多相关Go reflect反射内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!