Golang reflect反射的使用实例

作者:常鱼 时间:2024-05-05 09:32:17 

首先有一段以下结构体的定义

type User struct {
UserName string
UserId   int `name:"uid"`
}

初始化一个结构体的实例

u := User{"octoboy", 101}

获取字段名

首先获取变量的Type变量

t := reflect.TypeOf(u)

需要注意的是,如果传入的u是个指针,比如&User{"octoboy", 101}

if t.Kind() == reflect.Ptr {
t = t.Elem()
}

这里通过Kind()函数获取变量的类型,判断如果类型为指针 需要使用Elem()获取指针指向的内容。

然后遍历结构体的字段,获取其字段名称

for i := 0; i < t.NumField(); i++ {
fmt.Println(t.Field(i).Name)
}

输出结果:

UserName

UserId

获取字段类型和值

v := reflect.ValueOf(u)
if v.Kind() == reflect.Ptr { //类型为指针 需要取elem
v = v.Elem()
}

获取字段的值或者赋值,需要用到ValueOf方法

for i := 0; i < v.NumField(); i++ {
//v.Field(i).Int() v.Field(i).String() 都可以把值返回出来,相当于断言 类型不匹配会直接panic
//直接断成interface 任意类型
fmt.Println(v.Field(i).Interface())
}

输出结果:

zyg

101

继续输出成员变量的类型

for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Field(i).Kind())
}

输出结果:

string

int

设置字段值

静态赋值

//设置字段值
va := reflect.ValueOf(&u) //这里必须使用指针 否则后面调用Set无法使用无地址的值
if va.Kind() == reflect.Ptr { //类型为指针 需要取elem 意为取它指向的内容值
va = va.Elem()
for i := 0; i < va.NumField(); i++ {
//两种方法取设置字段的值,第二种更为统一
if va.Field(i).Kind() == reflect.String {
//重要 如果需要使用set取修改u中的值,需要在ValueOf中传入u的地址。否则会因为SetString使用了一个不能被寻址的值而造成panic
va.Field(i).SetString("octoboy")
}
if va.Field(i).Kind() == reflect.Int {
va.Field(i).Set(reflect.ValueOf(123))
}
}

interface切片映射成结构体(动态赋值)

//练手
values := []interface{}{"octoboy", 123}
for i := 0; i < va.NumField(); i++ {
if reflect.ValueOf(values[i]).Kind() == va.Field(i).Kind() {
va.Field(i).Set(reflect.ValueOf(values[i]))
}
}

打印以上两种结构题变量

输出结果:

&{octoboy 123}

进阶&mdash;map映射成结构体

有如下代码

//练习 把map映射成struct
set := map[string]interface{}{
"UserName": "zyg",
"UserId":   101,
"Age":      19,
"Sex":      1,
}
user := &User{}
MapToStruct(set, user)
fmt.Println(user)

要求将map映射到user结构题中,即如果User的字段名如存在于map的key中,则将对应的value值赋给user结构题的成员变量

有如下实现

//str类型为interface{} 代表可以传入任意的结构体
func MapToStruct(m map[string]interface{}, str interface{}) {
val := reflect.ValueOf(str)
if val.Kind() != reflect.Ptr {//必须是指针 否则无法用Set赋值
panic(any("must be ptr!"))
}
val = val.Elem()
if val.Kind() != reflect.Struct { //指针指向的必须是结构体
panic(any("must be struct"))
}
for i := 0; i < val.NumField(); i++ {
name := val.Type().Field(i).Name //value转type后取字段名称
if v, ok := m[name]; ok {        //如果根据tag做映射,就使用val.Type().Field(i).Tag.Get("name")作为key
if reflect.ValueOf(v).Kind() == val.Field(i).Kind() {
val.Field(i).Set(reflect.ValueOf(v))
}
}
}
}

来源:https://blog.csdn.net/kingu_crimson/article/details/127665684

标签:Golang,reflect,反射
0
投稿

猜你喜欢

  • 50个常用sql语句 网上流行的学生选课表的例子

    2012-07-11 16:02:01
  • 好玩的vbs微信小程序之语言播报功能

    2023-04-27 12:54:29
  • MySQL transaction事务安全示例讲解

    2024-01-25 17:47:38
  • js显示动态时间的方法详解

    2024-05-05 09:12:35
  • Python常用编译器原理及特点解析

    2021-09-04 05:10:11
  • python中base64编码简介

    2023-09-21 20:26:12
  • 10个有用的Python字符串函数小结

    2023-08-13 11:26:28
  • MySQL 复制表的方法

    2024-01-21 02:22:50
  • python神经网络特征金字塔FPN原理

    2023-12-20 02:21:01
  • Jupyter安装拓展nbextensions及解决官网下载慢的问题

    2023-11-24 20:50:54
  • opencv+python实现图像矫正

    2022-09-28 09:28:14
  • python爬虫设置每个代理ip的简单方法

    2022-11-01 19:18:52
  • python起点网月票榜字体反爬案例

    2021-03-11 02:56:05
  • Python数据挖掘中常用的五种AutoEDA 工具总结

    2022-05-20 02:49:51
  • django 基于中间件实现限制ip频繁访问过程详解

    2022-06-24 08:38:43
  • Python递归函数特点及原理解析

    2023-12-02 19:40:40
  • vue新玩法VueUse工具库具体用法@vueuse/core详解

    2023-07-02 16:55:44
  • Python 分享10个PyCharm技巧

    2021-11-18 11:03:41
  • 使用Spring.Net框架实现多数据库

    2024-01-14 08:02:22
  • vue之prop与$emit的用法说明

    2024-05-09 15:20:41
  • asp之家 网络编程 m.aspxhome.com