Golang反射的使用

反射的基本介绍:

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

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

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

 

类型的相互转换:

实例1:

package main

import (
	"fmt"
	"reflect"
)

type student struct {
	Name string
	Age  int
}

//修改简单数据类型
func changeData(i interface{}) {
	value := reflect.ValueOf(i)
	fmt.Println("kind:", value.Kind())
	value.Elem().SetInt(30)

}

//修改结构体类型数据
func ModityData(i interface{}) {
	value := reflect.ValueOf(i)
	fmt.Println(value.Kind())
	value.Elem().Field(0).SetString("江洲你好!")
	value.Elem().Field(1).SetInt(33333)

}

//通过反射 改变结构体对应字段的值
func main() {
	stu := student{Name: "jiangzhou", Age: 23}
	fmt.Println("原数据为:", stu)
	ModityData(&stu)
	fmt.Println("通过反射改变数据之后的值为:", stu)
}

//通过反射改变基本数据类型的值
func main02() {
	num := 10
	fmt.Println("原来数据是:", num)
	changeData(&num)
	fmt.Println("改变之后的数据是:", num)

}

//反射的基本使用: 类型  value  以及value与数据的相互转换
func main01() {
	stu := student{Name: "jiangzhou", Age: 23}
	typeOf := reflect.TypeOf(stu)
	fmt.Println(typeOf, typeOf.Kind())
	fmt.Println("执行value操作")
	value := reflect.ValueOf(stu)
	fmt.Println(value)
	interface1 := value.Interface()
	stu1 := interface1.(student)
	fmt.Println(stu1, stu1.Name, stu1.Age)

}

实例2:

package main

import (
	"fmt"
	"reflect"
)

/*
主要功能:1、取出结构体 tag中json对应的内容
*/
type Stu struct {
	Name string `json:"name"`
	Age int `json:"age"`
	Address string `json:"address"`
}

func(s Stu) Print1()  {
	fmt.Println(s.Name,s.Age,s.Address)
}
func (s Stu)Update1 () {
	s.Address="重庆"
	s.Age+=1
}
func (s Stu)GetNum(n1 ,n2 int) int {
	return n1+n2
}


func showTag(i interface{})  {
	if reflect.TypeOf(i).Kind()!=reflect.Struct {
		fmt.Println("不是结构体类型 ")
		return
	}
	varlue:=reflect.ValueOf(i)
	type1:=reflect.TypeOf(i)
	num:=varlue.NumField()
	for i:=0;i<num;i++{
		fmt.Print("结构体第",i,"个字段为:",varlue.Field(i))
		tag:=type1.Field(i).Tag  //获取标签
		fmt.Println("\t",tag,tag.Get("json")/*获取json对应的便签*/)
	}
	fmt.Println("执行方法的调用")
	num1 := varlue.NumMethod()  //标记:方法名一定要大写,不然会找不到对应的方法
	fmt.Println("结构体方法的个数为:",num1)
	varlue.Method(1).Call(nil)
	args:=[]reflect.Value{reflect.ValueOf(10),reflect.ValueOf(20)}

	call := varlue.Method(0).Call(args)
	fmt.Println(call[0].Int())
	fmt.Println("通过断言来执行的操作:")
	i2 := call[0].Interface()
	res,ok:=i2.(int)
	fmt.Println(res,ok)

}
func main() {
	stu:=Stu{Name:"jiangzhou",Age:23,Address:"cq"}
	showTag(stu)
}

实例3

以下实例为测试用例(golang自带了测试框架,测试文件命名规则:XX_test.go。如以下实例的文件名称为:refelect_test.go;测试方法名称命名规则为:TestXxx,以下测试方法名称为:TestReflectFunc)

package main

import (
	"testing"
)

func TestReflectFunc(t *testing.T)  {
	call1:= func(v1 int,v2 int) {
		t.Log(v1,v2)
	}
	call2:= func(v1 int,v2 int,s string) {
		t.Log(v1,v2,s)
	}
	call1(1,2)
	call2(1,2,"call2")

}

通过反射完成测试方法的调用:

package main

import (
	"reflect"
	"testing"
)

func TestReflectFunc(t *testing.T)  {
	call1:= func(v1 int,v2 int) {
		t.Log(v1,v2)
	}
	call2:= func(v1 int,v2 int,s string) {
		t.Log(v1,v2,s)
	}
	var (
		function reflect.Value
		inValue []reflect.Value
		n int
	)
	bridge:= func(call interface{},args ...interface{}) {
		n=len(args)
		inValue=make([]reflect.Value,n)
		for i:=0;i<n;i++{
			inValue[i]=reflect.ValueOf(args[i])
		}
		function=reflect.ValueOf(call)
		function.Call(inValue)
	}
	bridge(call1,1,2)
	bridge(call2,1,2,"call2")

}

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

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

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

实例4

package main

import (
	"encoding/json"
	"fmt"
)

type Stu1 struct {
	Name string `json:"stuName"`
	Age int `json:"stuAge`
	Address string `json:"StuAddress"`
}
func main() {
	stu:=Stu1{Name:"jiangzhou",Age:23,Address:"cq"}
	data,_:=json.Marshal(stu)
	fmt.Println(string(data))
}

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

猜你喜欢

转载自blog.csdn.net/weixin_42117918/article/details/86098733
今日推荐