17.golang之反射快速入门

本文探讨了如何利用反射在Go语言中序列化结构体并根据Tag动态调用函数。通过实例展示了如何操作基本类型、interface{}

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 先看一个问题来引出反射

package main
import (
	"fmt"
	"encoding/json"
)

// 先看一个问题,引出反射的使用场景

type Monster struct {
	Name string `json: "monsterName"`
	Age int `json: "monsterAge"`
	Sal float64 `json: "monsterSal"`
	Sex string `json: "monsterSex"`
}

func main() {
	m := Monster{
		Name: "孙悟空",
		Age: 5000,
		Sal: 18888.999,
		Sex: "男",
	}
	data,_ := json.Marshal(m)
	fmt.Println("json result:",string(data))
}

问题1:

为什么序列化后的,key-val的key值是Tag值,而不是字段的名称,比如:不是Name而是monsterName

引出反射:学习完reflect后,回来解决

2.使用反射机制,编写函数的适配器,桥连接

要求如下:

1)定义了两个匿名函数

test1 := func(v1 int, v2 int) {

        t.Log(v1,v2)

}

2)定义一个适配器函数用作统一处理接口,其大致结构如下:

bridge := func(call interface{},args...interface{}){

        // 内容

}

// 实现调用test1对应的函数

bridge(test1,1,2)

// 实现调用test2对应的函数

bridge(test2,1,2,"test2")

3)要求使用反射机制完成(note: 学习reflect后来解决)'

3. 反射的基本介绍

1)反射可以在运行时动态获取变量的各种信息,比如变量的类型(type),类别(kind)

2)如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法)

3)通过反射,可以修改变量的值,可以调用关联的方法

4)使用反射,需要import ("reflect")

5)示意图:

 4. 反射的应用场景

反射常见的应有场景有以下两种

1)不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这种需要对函数或方法反射。例如:以下这种桥接模式。

 第一个参数funcPtr以接口的形式传入函数指针,函数参数args以可变参数的形式传入,bridge函数中可以用反射来动态执行funcPtr函数

2)对结构体序列化时,如果结构体有指定的Tag,也会使用到反射生成对应的字符串

5.反射重要的函数和概念

1)reflect.TypeOf(变量名),获取变量的类型,返回reflect.Type类型

2)reflect.ValueOf(变量名),获取变量的值,返回reflect.Value类型reflect.Value是一个结构体类型。【看文档】,通过reflect.Value,可以获取到关于该变量的很多信息

 

3)变量、interface{} 和 reflect.Value 是可以相互转换的,在实际开发中,会经常使用到。

示意图如下:

 

 6. 反射的快速入门

快速入门说明

1)请编写一个案例,演示对(基本数据类型、interface{}、reflect.Value)进行反射的基本操纵

代码演示:

package main
import (
	"fmt"
	"reflect"
)

// 专门演示反射
func reflectTest01(b interface{}) {
	// 通过反射获取的传入的变量的type,kind值
	
	// 1. 先获取到 reflect.Type
	rTyp := reflect.TypeOf(b)
	fmt.Println("rType=",rTyp)
	
	// 2. 获取到 reflect.Value
	rVal := reflect.ValueOf(b)
	n2 := 2 + rVal.Int()
	// rVal.Int()等价于
	// rVal.Interface()
	// rVal.(int)
	fmt.Println("n2=",n2)
	fmt.Printf("rVal=%v  rVal type=%T\n",rVal,rVal)

	// 下面我们将rVal转成interface{}
	iV := rVal.Interface()
	// 将interface{} 通过类型断言转成需要的类型
	num2 := iV.(int)
	fmt.Println("num2=",num2)
}
func main() {
	// 请编写一个案例,演示对(基本数据类型,interface{},reflect.Value)进行反射的基本操作
	// 1. 先定义一个int
	var num int = 100
	reflectTest01(num)
}

2)请编写一个案例,演示对(结构体类型、interface{}、reflect.Value)进行反射的基本操作

代码演示:

package main
import (
	"fmt"
	"reflect"
)

type Student struct{
	Name string
	Age int
}
type Monster struct{
	Name string
	Age int
}

// 专门演示反射【对结构体的反射】
func reflectTest02(b interface{}) {
	// 通过反射获取的传入的变量 type,kind值
	// 1. 先获取到 reflect.Type
	rTyp := reflect.TypeOf(b)
	fmt.Println("rType=",rTyp)

	// 2. 获取到reflect.Value
	rVal := reflect.ValueOf(b)
	// 下面我们将 rVal 转成 interface{}
	iV := rVal.Interface()
	fmt.Printf("iv=%v iv type=%T\n",iV,iV)
	fmt.Println(iV.(Student))
}

func main() {
	// 演示对结构体的反射
	// 1. 定义一个Student的结构体
	stu := Student {
		Name: "tom",
		Age: 20,
	}
	reflectTest02(stu)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值