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}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值