golang reflect学习

本文详细介绍了Go语言中reflect包的基础使用,包括ValueOf和TypeOf函数的应用,动态修改参数值、函数调用、结构体tag获取,以及根据kind处理不同类型。通过实例展示了如何利用反射进行参数操作和功能实现。
摘要由CSDN通过智能技术生成

首先是定义
reflect是golang中运行时动态的调用对象的方法和属性的包
然后是使用
reflect最基础的使用就是获取对象的值和类型,方法是reflect.ValueOf和reflect.TypeOf

type aaa struct {
	A int
	B string
	C *time.Time
}

func main() {
	aa := aaa{
		A: 12,
		B: "haha",
	}
	//结构体struct
	ReflectValue := reflect.ValueOf(aa)//{12 haha <nil>}
	ReflectType := reflect.TypeOf(aa)//main.aaa kind=struct
	//int
	bb := 1
	ReflectValue = reflect.ValueOf(bb)//1
	ReflectType = reflect.TypeOf(bb)//int  kind=int
	//字符串
	cc :="哈哈"
	ReflectValue = reflect.ValueOf(cc)//哈哈
	ReflectType = reflect.TypeOf(cc)//string  kind=string
	//map
	dd := map[string]string{
		"aaa": "bbb",
		"ccc": "ddd",
	}
	ReflectValue = reflect.ValueOf(dd)//map[aaa:bbb ccc:ddd]
	ReflectType = reflect.TypeOf(dd)//map[string]string  kind=map
	//切片和数组
	ee :=[]string{"bbb", "ddd"}
	ReflectValue = reflect.ValueOf(ee)//[bbb ddd]
	ReflectType = reflect.TypeOf(ee)//[]string kind = slice
	ff := [2]string{"bbb", "ddd"}
	ReflectValue = reflect.ValueOf(ff)//[bbb ddd]
	ReflectType = reflect.TypeOf(ff)//[2]string kind = array
	//chan 通道
	gg := make(chan int, 10)
	ReflectValue = reflect.ValueOf(gg)//0xc000116000 一个内存地址
	ReflectType = reflect.TypeOf(gg)//chan int  kind = chan
	//func 
	hh := func() {
		println("我是一个function")
	}
	ReflectValue = reflect.ValueOf(hh)//0x1186dc0 一个内存地址
	ReflectType = reflect.TypeOf(hh)// func() kind = func
	//ptr 指针
	ii := &aa
	ReflectValue = reflect.ValueOf(ii)//&{12 haha <nil>}
	ReflectType = reflect.TypeOf(ii)//*main.aaa kind = ptr
	fmt.Println(ReflectValue)
	fmt.Println(ReflectType)
	fmt.Println(ReflectValue.Kind())

}

通过上面各种数据类型的反射使用,相信应该已经能够明白ValueOf和TypeOf的基本用法了吧。其中value.kind反回的是基础类型,type返回的是当前数据类型。

接下来说一下使用的场景

1.通过elem修改参数值,注意:要修改参数值那么ValueOf里面要传入的一定是参数的值针!!!如果传入的不是参数就会panic
例子

	aa := aaa{
		A: 12,
		B: "haha",
	}

	ReflectValue := reflect.ValueOf(&aa)
	// ReflectType := reflect.TypeOf(&aa)
	fmt.Println(ReflectValue.Elem())
	v := ReflectValue.Elem()
	fmt.Println(v.FieldByName("B").CanSet())
	if v.FieldByName("B").CanSet() {
		v.FieldByName("B").SetString("hehe")
	}
	fmt.Println(aa)

运行输出

{12 haha <nil>}
true
{12 hehe <nil>}

可以看到变量aa里面B的值已经被修改了

2.动态调用函数 通过Call方法

package main

import (
	"fmt"
	"reflect"
	"errors"
)

//动态调用函数(有参,无参,有返回值)
type T struct {}

func (t *T) Do() {
	fmt.Println("Hello, world!")
}

func (t *T) DoWithPara(name string, index int) {
	fmt.Println("Hello, ", name, index)
}

func (t *T) DoWithErr() (string, error){
	return "hello, world", errors.New("new error")
}

func main() {
	name1 := "Do"
	name2 := "DoWithPara"
	name3 := "DoWithErr"
	t := new(T)

	reflect.ValueOf(t).MethodByName(name1).Call(nil)

	name := reflect.ValueOf("world")
	index := reflect.ValueOf(1234)
	in := []reflect.Value{name, index}
	reflect.ValueOf(t).MethodByName(name2).Call(in)

	ret := reflect.ValueOf(t).MethodByName(name3).Call(nil)
	fmt.Println(ret[0], ret[1].Interface().(error))
}

3.获取结构体的tag标签

type T struct {
	A int `json:"aaa" test:"aaatest"`
	B string `json:"bbb" test:"bbbtest"`
}

func main() {
	t := T{
		A: 123456,
		B: "helloworld",
	}
	tt := reflect.TypeOf(t)
	for i := 0; i < tt.NumField(); i++ {
		field := tt.Field(i)
		if json, ok := field.Tag.Lookup("json"); ok {
			fmt.Println(json)
		}

		test := field.Tag.Get("test")
		fmt.Println(test)
	}
}

4.通过kind()处理不同分支

	a := "haha"
	t := reflect.TypeOf(a)
	switch t.Kind() {
	case reflect.Int:
		fmt.Println("int")
	case reflect.String:
		fmt.Println("string")
	default:
		fmt.Println("Unknown")
	}

参考
https://blog.csdn.net/chen1415886044/article/details/104929244
https://blog.csdn.net/mrbuffoon/article/details/85637417

Go语言中的reflect包提供了一种对程序的静态类型进行操作的方法,即可以在程序运行时动态地调用、检查和更改变量、类型和方法。 首先,reflect包提供了两个重要的类型:Type和Value。Type表示变量的类型,Value则表示变量的值。可以通过reflect.TypeOf和reflect.ValueOf来获取一个变量的Type和Value。 使用reflect包,我们可以在运行时获取变量的类型和值的一些基本信息,例如判断一个变量是否是某个特定类型,或者获取一个变量的名称和值。这在某些情况下可能是非常有用的,比如在编写通用的函数时,需要对不同类型的变量做相同的处理。 此外,reflect包还提供了一些函数来获取、设置和调用变量、类型和方法的具体信息。可以使用reflect.Value的相关方法来获取和设置变量的值,也可以使用reflect.Type的相关方法来获取类型的信息。使用reflect包还可以动态地调用某个值的方法。 需要注意的是,使用reflect包可能会导致一些性能上的损失,因为在运行时需要通过反射来获取变量的信息。因此,在性能要求较高的场景下,尽量避免使用反射。 总结而言,reflect包为我们提供了一种在运行时对变量、类型和方法进行操作的方法,可以通过反射来获取、设置和调用它们的信息。但是,需要注意在性能要求较高的情况下,尽量避免使用反射。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值