当前位置: 首页 > article >正文

Golang 进阶5—— 反射

Golang 进阶5—— 反射

注意,该文档只适合有编程基础的同学,这里的go教程只给出有区别的知识点

反射:

  • 反射可以在运行时动态获取变量的各种信息, 比如变量的类型、 类别等信息。
  • 如果是结构体变量,还可以获取结构体本身的信息(结构体的字段、方法)。
  • 通过反射, 可以修改变量的值,可以调用关联的方法。
  • 使用反射, 需要import(“reflect”)
1.1 main函数
package main

import (
	"fmt"
	"reflect"
)

// 利用一个函数, 函数的参数定义为空接口
// 空接口没有任何方法,所以可以理解为所有类型都实现了空接口
// 也可以理解为我们可以把任何一种类型赋值给空接口
func testReflect (data interface{}) {
	// 1、 调用 TypeOf函数, 返回reflect.Type 类型的数据
	fmt.Println("data type is ", reflect.TypeOf(data))

	// 2、 调用 ValueOf函数, 返回reflect.Value 类型的数据
	reVal := reflect.ValueOf(data)
	fmt.Println("data value is ", reVal)

	// 3、 如果要获取具体类型的值, 可以调用 Int 方法
	sum := 100 + reVal.Int()
	fmt.Println("sum is ", sum)

	// 4、 reVal 转成空接口
	i2  := reVal.Interface()
	fmt.Println("i2 is ", i2)

	// 5、类型断言
	n := i2.(int)
	n2 := n + 200
	fmt.Println("n2 is ", n2)

	fmt.Println("i2 type is ", reflect.TypeOf(i2))
}
1.2 输出结果
(base) PS E:\Goproject\src\gocode\testproject03> go run .\main\main.go
data type is  int
data value is  10
sum is  110
i2 is  10
n2 is  210
i2 type is  int
1.3 结构体情况
import (
	"fmt"
	"reflect"
)

type Student struct {
	Name string
	Age int
}

// 利用一个函数, 函数的参数定义为空接口
// 空接口没有任何方法,所以可以理解为所有类型都实现了空接口
// 也可以理解为我们可以把任何一种类型赋值给空接口
func testReflect (data interface{}) {
	// 1、 调用 TypeOf函数, 返回reflect.Type 类型的数据
	fmt.Println("data type is ", reflect.TypeOf(data))

	// 2、 调用 ValueOf函数, 返回reflect.Value 类型的数据
	reVal := reflect.ValueOf(data)
	fmt.Println("data value is ", reVal)

	// 3、 reVal 转成空接口
	i2 := reVal.Interface()
	fmt.Println("i2 is ", i2)

	if s, ok := i2.(Student); ok {
		fmt.Println("i2 is student:", s.Name)
	} else {
		fmt.Println("i2 is not a student")
	}
}

func main () {
	stu1 := Student{"xiaoxiao", 18}
	testReflect(stu1)
}
1.4 输出结果
(base) PS E:\Goproject\src\gocode\testproject03> go run .\main\main.go
data type is  main.Student
data value is  {xiaoxiao 18}
i2 is  {xiaoxiao 18}
i2 is student: xiaoxiao
1.5 获取变量类别
import (
	"fmt"
	"reflect"
)

type Student struct {
	Name string
	Age int
}

// 利用一个函数, 函数的参数定义为空接口
// 空接口没有任何方法,所以可以理解为所有类型都实现了空接口
// 也可以理解为我们可以把任何一种类型赋值给空接口
func testReflect (data interface{}) {
	// 1、 调用 TypeOf函数, 返回reflect.Type 类型的数据
	reType := reflect.TypeOf(data)
	fmt.Println("data type is ", reType)

	// 2、 调用 ValueOf函数, 返回reflect.Value 类型的数据
	reVal := reflect.ValueOf(data)
	fmt.Println("data value is ", reVal)

	// 3、 获取变量的类别(大范围)
	k1 := reVal.Kind()
	fmt.Println("data kind is ", k1)

	k2 := reType.Kind()
	fmt.Println("data kind is ", k2)

	// 4、 获取变量的类型 (小范围)
	i2 := reVal.Interface()

	if n, ok := i2.(Student); ok {
		fmt.Println("n is ", n)
	} else {
		fmt.Println("n is not Student")
	}

}

func main () {
	stu1 := Student{"xiaoxiao", 18}
	testReflect(stu1)
}
1.6 输出结果
(base) PS E:\Goproject\src\gocode\testproject03> go run .\main\main.go
data type is  main.Student
data value is  {xiaoxiao 18}
data kind is  struct
data kind is  struct
n is  {xiaoxiao 18}
1.7 对结构体操作
// 1. 定义结构体
type Student struct {
	Name string
	Age  int
}

// 2. 给结构体绑定方法
func (stu Student) Print() {
	fmt.Print("调用了Print方法")
	fmt.Println(stu)
}

func (stu Student) GetSum(n1, n2 int) int {
	return n1 + n2
}

func (stu Student) Set(name string, age int) {
	stu.Name = name
	stu.Age = age
}

func testReflect(data interface{}) {
	reVal := reflect.ValueOf(data)

	// 检查 data 是否是指针,并获取指向的值
	if reVal.Kind() == reflect.Ptr {
		reVal = reVal.Elem()
	}

	fmt.Println(reVal)

	// 获取结构体中字段的数量
	n1 := reVal.NumField()
	fmt.Println("字段的数量:", n1)

	for i := 0; i < n1; i++ {
		// 输出字段
		fmt.Printf("字段 %d 的名字是 %s, 对应的值为 %v \n", i, reVal.Type().Field(i).Name, reVal.Field(i))
	}

	// 获取结构体的方法数量
	n2 := reVal.NumMethod()
	fmt.Println("方法的数量:", n2)

	// 输出方法
	for i := 0; i < n2; i++ {
		// 输出方法
		fmt.Printf("方法 %d 的名字是 %s \n", i, reVal.Type().Method(i).Name)
	}

	// 调用方法, 调用的方法首字母必须大写
	reVal.MethodByName("Print").Call(nil)

	// 调用GetSum方法
	// 定义Value切片
	var params []reflect.Value
	params = append(params, reflect.ValueOf(10))
	params = append(params, reflect.ValueOf(20))
	sum := reVal.MethodByName("GetSum").Call(params)
	fmt.Println("sum = ", sum[0])
}

func main() {
	stu := Student{Name: "Tom", Age: 18}
	testReflect(stu) // 传入 stu 的指针
}
1.8 输出结果
(base) PS E:\Goproject\src\gocode\testproject03> go run .\main\main.go
{Tom 18}
字段的数量: 2
字段 0 的名字是 Name, 对应的值为 Tom
字段 1 的名字是 Age, 对应的值为 18
方法的数量: 3
方法 0 的名字是 GetSum
方法 1 的名字是 Print
方法 2 的名字是 Set
调用了Print方法{Tom 18}
sum =  30
1.9 改值
import (
	"fmt"
	"reflect"
)

// 1. 定义结构体
type Student struct {
	Name string
	Age  int
}

// 2. 给结构体绑定方法
func (stu Student) Print() {
	fmt.Print("调用了Print方法")
	fmt.Println(stu)
}

func (stu Student) GetSum(n1, n2 int) int {
	return n1 + n2
}

func (stu Student) Set(name string, age int) {
	stu.Name = name
	stu.Age = age
}

func testReflect(data interface{}) {
	reVal := reflect.ValueOf(data)

	// 通过setInt方法修改值
	n := reVal.Elem().NumField()
	fmt.Println("结构体中字段个数为:", n)
	
	reVal.Elem().Field(0).SetString("Jack")
	reVal.Elem().Field(1).SetInt(30)
}

func main() {
	stu := Student{Name: "Tom", Age: 18}
	testReflect(&stu) // 传入 stu 的指针
	fmt.Println(stu)
}
1.10 输出结果
(base) PS E:\Goproject\src\gocode\testproject03> go run .\main\main.go
结构体中字段个数为: 2
{Jack 30}

http://www.kler.cn/news/334933.html

相关文章:

  • 通过python-api使用openai的gpt
  • 算法讲解—最小生成树(Kruskal 算法)
  • 微服务实战——SpringCache 整合 Redis
  • “衣依”服装销售平台:Spring Boot框架的设计与实现
  • Excel 表列名称(26进制)
  • C语言—顺序表(含通讯录项目)
  • 网约班车升级手机端退票
  • Python PyQt5 使用setStyleSheet设置QLabel字体样式
  • Cilium-实战系列-(二)Cilium-Multi Networking-多网络
  • DualGS:高效人体体积视频渲染技术,实现复杂4D数字人表演的实时播放引言
  • U mamba配置问题;‘KeyError: ‘file_ending‘
  • openpnp - 图像传送方向要在高级校正之前设置好
  • 模拟器GSN3之DHCP动态分配IP地址配置案例
  • 【DataLoom】智能问数 - 自然语言与数据库交互
  • Golang | Leetcode Golang题解之第452题用最少数量的箭引爆气球
  • 基于Python的人工智能应用案例系列(14):Fashion MNIST图像分类CNN
  • Pikachu-Sql-Inject - 暴力破解
  • Luminar激光雷达公司裁员重组的深度分析
  • 力扣10.5
  • MQTT--Java整合EMQX