0
点赞
收藏
分享

微信扫一扫

[Go关于反射] reflect包

kolibreath 2022-04-06 阅读 97
golang

参考自liwenzhou

ORM库要用到, 记录一下.

文章目录

reflect.TypeOf() 获取对象类型

在Go语言中,使用reflect.TypeOf()函数可以获得任意值的类型对象(reflect.Type

程序通过类型对象可以访问任意值的类型信息。

func reflectType(x interface{}){
	v := reflect.TypeOf( x )
	fmt.Printf("type: %v\n",v )
}
func main(){
	var a float32 = 3.14
	reflectType( a ) // type: float32
	var b int64 = 100
	reflectType( b ) // type: int64
}

type name和type kind

type tk int64

var(
	a *float32 //指针
	b tk //自定义类型
	by byte //类型别名
	user = User{ "cl",20 }
)

type User struct {
	Name string
	Age int
}

func reflectType(x interface{} ){
	temp := reflect.TypeOf( x )
	fmt.Printf("type: %v kind: %v\n", temp.Name(),temp.Kind() )
}

func main(){
	reflectType( a )
	reflectType( b )
	reflectType( by )  // byte是官方定义的类型,所以输出和自定义的不一样
	reflectType( user )
}

输出为

type:  kind: ptr
type: tk kind: int64
type: uint8 kind: uint8
type: User kind: struct

可以发现Kind总是比Type更接近底层, 而Type则是输出自定义类型的名字而不是底层

Go语言的反射中像数组、切片、Map、指针等类型的变量,它们的.Name()都是返回空。

reflect.ValueOf()

reflect.ValueOf()返回reflect.Value类型,其中包含了原始值的值信息。reflect.Value与原始值之间可以互相转换。

func reflectValue(x interface{}){
	v := reflect.ValueOf(x)
	k := v.Kind()
	switch k {
	case reflect.Int64:
		// v.Int()从反射中获取整型的原始值,然后通过int64()强制类型转换
		fmt.Printf("type is int64, value is %d\n", int64(v.Int()))
	case reflect.Float32:
		// v.Float()从反射中获取浮点型的原始值,然后通过float32()强制类型转换
		fmt.Printf("type is float32, value is %f\n", float32(v.Float()))
	case reflect.Float64:
		// v.Float()从反射中获取浮点型的原始值,然后通过float64()强制类型转换
		fmt.Printf("type is float64, value is %f\n", float64(v.Float()))
	}
}

func main() {
	var a float32 = 3.14
	var b int64 = 100
	reflectValue(a) // type is float32, value is 3.140000
	reflectValue(b) // type is int64, value is 100
}

reflect.Value.Elem()获取指针对应的值并修改

使用反射修改变量值

func reflectSetValue1(x interface{}) {
	v := reflect.ValueOf(x)
	if v.Kind() == reflect.Int64 {
		v.SetInt(200) //修改的是副本,reflect包会引发panic
	}
}
func reflectSetValue2(x interface{}) {
	v := reflect.ValueOf(x)
	//fmt.Println( v.Kind() )
	//fmt.Println( v.Elem().Kind() )
	// 反射中使用 Elem()方法获取指针对应的值
	if v.Elem().Kind() == reflect.Int64 {
		v.Elem().SetInt(200)
	}
}
func main() {
	var a int64 = 100
	// reflectSetValue1(a) //panic: reflect: reflect.Value.SetInt using unaddressable value
	reflectSetValue2(&a)
	fmt.Println(a)
}

结构体反射

任意值通过reflect.TypeOf()获得反射对象信息后,如果它的类型是结构体

可以通过反射值对象(reflect.Type)的NumField()Field()方法获得结构体成员的详细信息。

type student struct {
	Name  string `json:"name"`
	Score int    `json:"score"`
}

func main() {
	stu1 := student{
		Name:  "小王子",
		Score: 90,
	}

	t := reflect.TypeOf(stu1)
	fmt.Println(t.Name(), t.Kind()) // student struct
	// 通过for循环遍历结构体的所有字段信息
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		fmt.Printf("name:%s index:%d type:%v json tag:%v\n", field.Name, field.Index, field.Type, field.Tag.Get("json"))
	}

	// 通过字段名获取指定结构体字段信息
	if scoreField, ok := t.FieldByName("Score"); ok {
		fmt.Printf("name:%s index:%d type:%v json tag:%v\n", scoreField.Name, scoreField.Index, scoreField.Type, scoreField.Tag.Get("json"))
	}
}

遍历结构体包含的所有方法并调用

// 给student添加两个方法 Study和Sleep(注意首字母大写)
func (s student) Study() string {
	msg := "好好学习,天天向上。"
	fmt.Println(msg)
	return msg
}

func (s student) Sleep() string {
	msg := "好好睡觉,快快长大。"
	fmt.Println(msg)
	return msg
}

func printMethod(x interface{}) {
	t := reflect.TypeOf(x)
	v := reflect.ValueOf(x)

	fmt.Println(t.NumMethod())
	for i := 0; i < v.NumMethod(); i++ {
		methodType := v.Method(i).Type()
		fmt.Printf("method name:%s\n", t.Method(i).Name)
		fmt.Printf("method:%s\n", methodType)
		// 通过反射调用方法传递的参数必须是 []reflect.Value 类型
		var args = []reflect.Value{}
		v.Method(i).Call(args)
	}
}
举报

相关推荐

0 条评论