Chapter017 golang反射

上一章:Chapter016 goroutine协程 和 channel管道
下一章:Chapter018 golang tcp socket编程快速入门
官方文档:https://studygolang.com/pkgdoc

一、反射的使用场景

1、结构体标签
2、函数的适配器
3、甚至可以自己开发go框架

二、基本介绍

1、反射可以在运行时动态获取变量的各种信息,比如变量的类型(type)、类别(kind)
2、如果是结构体变量,还可以获取结构体本身的信息(包括结构体的字段、方法)
3、通过反射,可以修改变量的值,可以调用关联方法
4、使用反射,需要import reflect
在这里插入图片描述
5、示意图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、反射的相关函数

1、reflect.TypeOf,获取变量的类型,返回reflect.Type类型
在这里插入图片描述
2、reflect.ValueOf,获取变量的类型,返回reflect.ValueOf类型
在这里插入图片描述
3、变量、interface{}和reflect.Value是可以相互转换的
(1)将interface{}转换成reflect.Value

rval := reflect.ValueOf(b)

(2)将reflect.Value转换成interface{}

iVal := rVal.Interface()

(3)将interface{}转成原来的变量类型,使用类型断言

v := iVal.(Stu)

(4)转换关系图
在这里插入图片描述

四、反射快速入门

1、对基本数据类型

package main

import (
	"fmt"
	"reflect"
)

//演示反射  对基本数据类型
func reflectTest01(b interface{})  {
	//通过反射获取到传入变量类型type、类别kind、值

	//1、reflect.type  反射类型rTyp
	rTyp := reflect.TypeOf(b)
	fmt.Println("rType =",rTyp)

	//2、 reflect.Value
	rVal := reflect.ValueOf(b)
	fmt.Println("rVal =",rVal)
	fmt.Printf("rVal Type = %T\n",rVal)

	//3、 下面将rVal转回interface{}
	iV := rVal.Interface()
	//4、将interface{} 通过断言再重新转成需要的类型
	num2 :=iV.(int)
	fmt.Println("num2 =",num2)
	fmt.Printf("num2 Type = %T\n",num2)

}

func main()  {

	//基本数据类型
	var num int  = 100
	reflectTest01(num)
}

2、对结构体

package main

import (
	"fmt"
	"reflect"
)

//演示反射  对结构体
type Student struct {
	Name string
	Age int
}

func reflectTest02(b interface{}) {

	//1、reflect.type  反射类型rTyp
	rTyp := reflect.TypeOf(b)
	fmt.Println("rType =",rTyp)

	//2、 reflect.Value
	rVal := reflect.ValueOf(b)
	fmt.Println("rVal =",rVal)
	fmt.Printf("rVal Type = %T\n",rVal)

	//3、 下面将rVal转回interface{}
	iV := rVal.Interface()
	fmt.Println("iV =",iV)
	fmt.Printf("iV Type = %T\n",iV)
	//4、将interface{} 通过断言再重新转成需要的类型才能取出结构体内容
	stu,ok := iV.(Student)
	if ok{
		fmt.Println("stuName = ",stu.Name)
	}
}

func main()  {

	//结构体
	var stu Student
	stu.Name = "tom"
	stu.Age = 10
	reflectTest02(stu)
}

运行结果:
在这里插入图片描述
3、通过set来修改变量要用指针

package main

import (
	"fmt"
	"reflect"
)

func reflectTest03(b interface{})  {
	rVal := reflect.ValueOf(b)
	fmt.Println("rVal kind = ",rVal)
	rVal.Elem().SetInt(20)
}
func main()  {
	var num int  = 100
	//修改变量值
	reflectTest03(&num)
	fmt.Println(num)
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

五、反射的注意事项

1、reflect.ValueOf.Kind 或者 reflect.TypeOf.Kind返回常量
在这里插入图片描述

六、反射的应用

1、使用反射来调度结构体方法、字段、标签
(1)调度方法
在这里插入图片描述
在这里插入图片描述
(2)调度字段
在这里插入图片描述
(3)调度tag
在这里插入图片描述
在这里插入图片描述
(4)综合应用

package main

import (
	"fmt"
	"reflect"
)

type Monster struct {
	Name string `json:"name"`
	Age int		`json:"age"`
	Score float32	`json:"score"`
	Sex string		`json:"sex"`
	Adress string
}

func (s Monster) Print()  {
	fmt.Println("--start--")
	fmt.Println(s)
	fmt.Println("--end--")
}

func (s Monster)GetSum(n1,n2 int) int  {
	return n1+n2
}

func (s Monster)Set(name string,age int,score float32,sex string)  {
	s.Name = name
	s.Age = age
	s.Score = score
	s.Sex = sex
}

func TestStruct(a interface{})  {
	//获取reflect.Type类型
	typ := reflect.TypeOf(a)
	//获取reflect.Value类型
	val := reflect.ValueOf(a)
	//获取a对应类别
	kd := val.Kind()
	//不是结构体就退出
	if kd != reflect.Struct{
		fmt.Println("except struct")
		return
	}
	//获取到该结构体有多少字段
	num := val.NumField()
	fmt.Printf("this monster has %v 字段\n",num)
	//结构体所有字段
	for i:=0;i<num ;i++  {
		//value.Field返回字段,但是不能运算,要运算要转换
		fmt.Printf("Field %d : 值为%v\n",i,val.Field(i))
		//获取标签,要用typ.Field
		tagVal := typ.Field(i).Tag.Get("json")
		if tagVal !=""{
			fmt.Printf("Field %d:tag为%v\n",i,tagVal)
		}
	}
	//返回方法数目
	numOfMethed := val.NumMethod()
	fmt.Printf("struct has %v metheds\n",numOfMethed)

	//var params []reflect.Value
	//获取到第二个方法(按照函数名ASCII字母排序)并调用它
	val.Method(1).Call(nil)

	//调用结构体第一个方法Method(0)
	var params []reflect.Value
	params = append(params,reflect.ValueOf(10))
	params = append(params,reflect.ValueOf(40))
	res := val.Method(0).Call(params)  //传入参数[]reflect.Value
	fmt.Println("res=",res[0].Int())  //返回结果,返回的结果是[]reflect.Value
}

func main()  {
	var a  = Monster{
		Name:  "牛魔王",
		Age:   400,
		Score: 100.00,
		Sex:   "male",
		Adress: "中国",
	}
	TestStruct(a)
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杰西啊杰西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值