文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

深入了解Golang中reflect反射的使用

2023-05-20 05:34

关注

1. 介绍

在反射的世界里,我们拥有了获取一个对象的类型,属性及方法的能力。

在 Go 反射的世界里,有两种类型非常重要,是整个反射的核心,在学习 reflect 包的使用时,先得学习下这两种类型:

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包设置好环境变量,利用反射实现项目启动时运行时加载进环境!

环境变量KeyCONFIG_SERVER_NAMECONFIG_SERVER_IPCONFIG_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反射内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯