go语言通过反射来操作结构体中的数据

Go 判断传入的是否是一个结构体类型

用 reflect 包,判断 Kind() 是否为 reflect.Struct

go 复制代码
func isStruct(v interface{}) bool {
	if v == nil {
		return false
	}
	return reflect.TypeOf(v).Kind() == reflect.Struct
}

获取字段名,字段类型,字段标签

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

// 学生结构体
type Student struct {
	Name  string `json:"name" form:"userName"`
	Age   int    `json:"age"`
	Score int    `json:"score"`
}

// 获取结构体的信息
func (s Student) GetInfo() string {
	var str = fmt.Sprintf("姓名: %v, 年龄: %v, 成绩: %v", s.Name, s.Age, s.Score)
	return str
}

// 设置结构体的信息,这个参数应该是指针类型的【重要】
func (s *Student) SetInfo(name string, age int, score int) {
	s.Name = name
	s.Age = age
	s.Score = score
}

func (s Student) Print() {
	fmt.Println("这是一个打印的方法")
}

// 打印字段
func PrintStructField(s interface{}) {
	// 通过反射来获取变量的类型;t的值是: *main.Student; * 表示这是一个指针类型
	// 通过反射来获取变量的类型
	t := reflect.TypeOf(s)

	// 【关键修改1】如果是指针,先解引用拿到实际的结构体类型
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	// 【关键修改2】统一判断解引用后的类型是否是结构体
	if t.Kind() != reflect.Struct {
		fmt.Println("不是结构体类型")
		return
	}
	// 通过类型变量里面的Field可以获取结构体的字段
	filed := t.Field(0)
	fmt.Println(filed)
	fmt.Printf("获取字段名: %v\n", filed.Name)
	fmt.Printf("获取字段类型: %v\n", filed.Type)
	fmt.Printf("获取字段标签: %v\n", filed.Tag.Get("json"))
	fmt.Printf("获取字段标签: %v\n", filed.Tag.Get("form"))
}

// 入口函数
func main() {
	// 实例化这个结构体
	stu1 := Student{
		Name:  "张三",
		Age:   18,
		Score: 90,
	}
	// 传入的是一个指针,
	PrintStructField(&stu1)
}

{Name string json:"name" form:"userName" 0 0 false}

获取字段名: Name

获取字段类型: string

获取字段标签: name

获取字段标签: userName

通过 FieldByName 获取结构体中的字段

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

// 学生结构体
type Student struct {
	Name  string `json:"name" form:"userName"`
	Age   int    `json:"age"`
	Score int    `json:"score"`
}

// 获取结构体的信息
func (s Student) GetInfo() string {
	var str = fmt.Sprintf("姓名: %v, 年龄: %v, 成绩: %v", s.Name, s.Age, s.Score)
	return str
}

// 设置结构体的信息,这个参数应该是指针类型的【重要】
func (s *Student) SetInfo(name string, age int, score int) {
	s.Name = name
	s.Age = age
	s.Score = score
}

func (s Student) Print() {
	fmt.Println("这是一个打印的方法")
}

// 打印字段
func PrintStructField(s interface{}) {
	// 通过反射来获取变量的类型;t的值是: *main.Student; * 表示这是一个指针类型
	// 通过反射来获取变量的类型
	t := reflect.TypeOf(s)

	// 【关键修改1】如果是指针,先解引用拿到实际的结构体类型
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	// 【关键修改2】统一判断解引用后的类型是否是结构体
	if t.Kind() != reflect.Struct {
		fmt.Println("不是结构体类型")
		return
	}
	// 通过类型变量里面的Field可以获取结构体的字段
	filed, ok := t.FieldByName("Name")
	if ok {
		fmt.Printf("获取字段名: %v\n", filed.Name)
		fmt.Printf("获取字段类型: %v\n", filed.Type)
		fmt.Printf("获取字段标签: %v\n", filed.Tag.Get("json"))
		fmt.Printf("获取字段标签: %v\n", filed.Tag.Get("form"))
	}
}

// 入口函数
func main() {
	// 实例化这个结构体
	stu1 := Student{
		Name:  "张三",
		Age:   18,
		Score: 90,
	}
	// 传入的是一个指针,
	PrintStructField(&stu1)
}

获取字段名: Name

获取字段类型: string

获取字段标签: name

获取字段标签: userName

获取结构体有多少个字段

go 复制代码
// 打印字段
func PrintStructField(s interface{}) {
	// 通过反射来获取变量的类型;t的值是: *main.Student; * 表示这是一个指针类型
	// 通过反射来获取变量的类型
	t := reflect.TypeOf(s)

	// 【关键修改1】如果是指针,先解引用拿到实际的结构体类型
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	// 【关键修改2】统一判断解引用后的类型是否是结构体
	if t.Kind() != reflect.Struct {
		fmt.Println("不是结构体类型")
		return
	}
	// 获取结构体有多少个字段
	fmt.Printf("结构体有 %v 个字段\n", t.NumField())
}

结构体有 3 个字段

ps:注意值变量和类型变量哈

获取结构体属性对应的值

scss 复制代码
func PrintStructField(s interface{}) {
	v := reflect.ValueOf(s)
	fmt.Printf("获取结构体属性对应的值: %v\n", v.FieldByName("Name"))
}

for循环获取属性名和属性的类型

go 复制代码
// 打印字段
func PrintStructField(s interface{}) {
	t := reflect.TypeOf(s)
	var fieldCount = t.NumField()
	for i := 0; i < fieldCount; i++ {
		fmt.Printf("字段名: %v, 字段类型: %v\n", t.Field(i).Name, t.Field(i).Type)
	}
}

字段名: Name, 字段类型: string

字段名: Age, 字段类型: int

字段名: Score, 字段类型: int

获取结构体中的方法

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

// 学生结构体
type Student struct {
	Name  string `json:"name" form:"userName"`
	Age   int    `json:"age"`
	Score int    `json:"score"`
}

// 获取结构体的信息
func (s Student) GetInfo() string {
	var str = fmt.Sprintf("姓名: %v, 年龄: %v, 成绩: %v", s.Name, s.Age, s.Score)
	return str
}

// 设置结构体的信息,这个参数应该是指针类型的【重要】
func (s *Student) SetInfo(name string, age int, score int) {
	s.Name = name
	s.Age = age
	s.Score = score
}

func (s Student) Print() {
	fmt.Println("这是一个打印的方法")
}

// 打印字段
func PrintStructField(s interface{}) {
	// 通过反射来获取变量的类型;t的值是: *main.Student; * 表示这是一个指针类型
	// 通过反射来获取变量的类型

	t := reflect.TypeOf(s)
	// 获取结构体中的方法
    // 和结构体方法的顺序没有关系,和结构体方法的ASCII有关系
	method0 := t.Method(0)
	fmt.Println(method0.Name) // GetInfo
	fmt.Println(method0.Type) // func(main.Student) string
}

// 入口函数 
func main() {
	// 实例化这个结构体
	stu1 := Student{
		Name:  "张三",
		Age:   18,
		Score: 90,
	}
	// 传入的是一个指针,
	PrintStructField(stu1)
}

GetInfo func(main.Student) string

获取结构体中的方法名称和方法

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

// 学生结构体
type Student struct {
	Name  string `json:"name" form:"userName"`
	Age   int    `json:"age"`
	Score int    `json:"score"`
}

// 获取结构体的信息
func (s Student) GetInfo() string {
	var str = fmt.Sprintf("姓名: %v, 年龄: %v, 成绩: %v", s.Name, s.Age, s.Score)
	return str
}

// 设置结构体的信息,这个参数应该是指针类型的【重要】
func (s *Student) SetInfo(name string, age int, score int) {
	s.Name = name
	s.Age = age
	s.Score = score
}

func (s Student) Print() {
	fmt.Println("这是一个打印的方法")
}

// 打印字段
func PrintStructField(s interface{}) {
	// 通过反射来获取变量的类型;t的值是: *main.Student; * 表示这是一个指针类型
	// 通过反射来获取变量的类型

	t := reflect.TypeOf(s)
	// 获取结构体中的方法
	method, ok := t.MethodByName("Print")
	if ok {
		// 输出:Print
		fmt.Println(method.Name)
		// 输出: func(main.Student)
		fmt.Println(method.Type)
	}
}

// 入口函数
func main() {
	// 实例化这个结构体
	stu1 := Student{
		Name:  "张三",
		Age:   18,
		Score: 90,
	}
	// 传入的是一个指针,
	PrintStructField(stu1)
}

Print func(main.Student)

调用方法

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

// 学生结构体
type Student struct {
	Name  string `json:"name" form:"userName"`
	Age   int    `json:"age"`
	Score int    `json:"score"`
}

// 获取结构体的信息
func (s Student) GetInfo() string {
	var str = fmt.Sprintf("姓名: %v, 年龄: %v, 成绩: %v", s.Name, s.Age, s.Score)
	return str
}

// 设置结构体的信息,这个参数应该是指针类型的【重要】
func (s *Student) SetInfo(name string, age int, score int) {
	s.Name = name
	s.Age = age
	s.Score = score
}

func (s Student) Print() {
	fmt.Println("这是一个打印的方法")
}

// 打印字段
func PrintStructField(s interface{}) {
	// 通过反射来获取变量的类型;t的值是: *main.Student; * 表示这是一个指针类型
	// 通过反射来获取变量的类型

	v := reflect.ValueOf(s)
	// 调用方法, 第一个参数是方法的索引, 第二个参数是方法的参数
    // 如果方法没有  参数,需要在Call方法中写上nil,否则会报错
	v.Method(1).Call(nil)
    // 通过另外一种方式来进行调用方法
	v.MethodByName("Print").Call(nil)

    // 调用方法,接收方法返回来的值
	info := v.MethodByName("GetInfo").Call(nil)
    // [姓名: 张三, 年龄: 18, 成绩: 90]
	fmt.Println(info)
}

// 入口函数
func main() {
	// 实例化这个结构体
	stu1 := Student{
		Name:  "张三",
		Age:   18,
		Score: 90,
	}
	// 传入的是一个指针,
	PrintStructField(stu1)
}

这是一个打印的方法

调用方法修改结构体中的数据

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

// 学生结构体
type Student struct {
	Name  string `json:"name" form:"userName"`
	Age   int    `json:"age"`
	Score int    `json:"score"`
}

// 获取结构体的信息
func (s Student) GetInfo() string {
	var str = fmt.Sprintf("姓名: %v, 年龄: %v, 成绩: %v", s.Name, s.Age, s.Score)
	return str
}

// 设置结构体的信息,这个参数应该是指针类型的【重要】
func (s *Student) SetInfo(name string, age int, score int) {
	s.Name = name
	s.Age = age
	s.Score = score
}

func (s Student) Print() {
	fmt.Println("这是一个打印的方法")
}

// 打印字段
func PrintStructField(s interface{}) {
	// 通过反射来获取变量的类型;t的值是: *main.Student; * 表示这是一个指针类型
	// 通过反射来获取变量的类型

	v := reflect.ValueOf(s)
	// 调用方法并且传入参数
	var params []reflect.Value // 定义一个切片,类型是 reflect.Value
	params = append(params, reflect.ValueOf("WangWen"))
	params = append(params, reflect.ValueOf(18))
	params = append(params, reflect.ValueOf(90))
	// call参数类型是:[]reflect.Value;因此前面我们需要声明一下参数的类型
	// 设置结构体的信息
	v.MethodByName("SetInfo").Call(params)
	// 调用方法,接收方法返回来的值

	info := v.MethodByName("GetInfo").Call(nil)
	fmt.Printf("获取到的信息是:%v", info)
}

// 入口函数
func main() {
	// 实例化这个结构体
	stu1 := Student{
		Name:  "张三",
		Age:   18,
		Score: 90,
	}
	// 传入的是一个指针,
	PrintStructField(&stu1)
}

获取到的信息是:姓名: WangWen, 年龄: 18, 成绩: 90

获取方法的数量

go 复制代码
// 打印字段
func PrintStructField(s interface{}) {
	// 通过反射来获取变量的类型;t的值是: *main.Student; * 表示这是一个指针类型
	// 通过反射来获取变量的类型

	v := reflect.ValueOf(s)
	// 获取方法的数量(格式)
	methodNum := v.NumMethod()
	fmt.Printf("方法的数量是:%v", methodNum)
}

通过反射修改结构体中的值

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

// 学生结构体
type Student struct {
	Name  string `json:"name" form:"userName"`
	Age   int    `json:"age"`
	Score int    `json:"score"`
}

// 获取结构体的信息
func (s Student) GetInfo() string {
	var str = fmt.Sprintf("姓名: %v, 年龄: %v, 成绩: %v", s.Name, s.Age, s.Score)
	return str
}

// 设置结构体的信息,这个参数应该是指针类型的【重要】
func (s *Student) SetInfo(name string, age int, score int) {
	s.Name = name
	s.Age = age
	s.Score = score
}

func (s Student) Print() {
	fmt.Println("这是一个打印的方法")
}

// 打印字段
func PrintStructField(s interface{}) {
	t := reflect.TypeOf(s)
	v := reflect.ValueOf(s)
	if t.Kind() != reflect.Ptr {
		fmt.Println("传入的参数不是指针类型")
		return
	} else if t.Elem().Kind() != reflect.Struct {
		fmt.Println("传入的参数不是结构体类型")
		return
	}
	// 修改结构体属性的值(也就是修改value的值)
	name := v.Elem().FieldByName("Name")
	name.SetString("大李四")
	age := v.Elem().FieldByName("Age")
	age.SetInt(20)
}

// 入口函数
func main() {
	// 实例化这个结构体
	stu1 := Student{
		Name:  "张三",
		Age:   18,
		Score: 90,
	}
	// 传入的是一个指针,
	PrintStructField(&stu1)
	fmt.Printf("%v\n", stu1)
}
相关推荐
人人都是软件工程师41 分钟前
16-并发编程(下):channel、select 与同步原语
go
imDwAaY43 分钟前
进程之间如何“对话”?一篇讲清六种进程间通信方式
后端·操作系统
知守观44 分钟前
同事的 SNAPSHOT 更新了,我三天后才拉到:Maven 更新检查被 _remote.repositories 静默跳过
java·后端·maven
斑鸠喳喳1 小时前
交换器 Exchanger
后端
霸道流氓气质1 小时前
MinIO 入门与实战:S3 兼容对象存储、Spring Boot 集成与 AI 应用文件管理
人工智能·spring boot·后端
我真是泰库辣1 小时前
我写了 300 行 Python,让代码替我在《三角洲行动》里吹口琴
后端
CaptainT1 小时前
先把例子跑起来:MySQL 环境与本文的示例数据
数据库·后端·mysql
程序猿乐锅1 小时前
【从0-1学习Python | 第四篇】Python 字符串和元组
java·开发语言·笔记·后端·python·学习
码事漫谈1 小时前
一条 ALTER TABLE 的跨库旅程:KFS 如何自动翻译 DDL
后端