GO之反射

一:反射的基本介绍

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

②:如果是结构体变量,还可以获取结构体声明的字段好方法;

③:通过反射,可以修改变量的值,可以钓鱼关联的方法;

④:反射,需要import "reflect"

二:反射的应用场景

①:不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这种需要对函数或方法反射;

②:对结构体的序列化时,如果结构体有指定tag,也会用到反射(go底层完成反射操作)。

三:反射重要的函数和概念

①:reflect.TypeOf(变量名),获取变量的类型,返回reflect.type类型;

②:reflect.ValueOf(变量名),获取变量的值,返回reflect.Value类型,reflect.Value是一个结构体,通过该结构体可以获取变量的更多信息;

③:变量,interface{}和reflect.Value是可以相互转化

四:反射的使用举例

package main

import (
	"fmt"
	"reflect"
)

//基本数据的反射
func reflectInt(i interface{}){
	//获取变量的type和kind值
	re_int_type := reflect.TypeOf(i)
	fmt.Printf("re_int_type=%v\n", re_int_type)

	//获取变量的值信息
	re_int_value := reflect.ValueOf(i)
	fmt.Printf("re_int_value=%T,re_int_value=%v\n", re_int_value, re_int_value)
	//不可以直接使用re_int_value,因为re_int_value实际上是reflect.Value类型并不是int
	num := 10 + re_int_value.Int()
	fmt.Printf("num=%v\n", num)

	//将re_int_value转为interface{}
	inter_value := re_int_value.Interface()
	//由于变量本身就是int型,故interface{}显示为int
	fmt.Printf("inter_value=%v,inter_value type=%T\n", inter_value, inter_value)
	//再转换成interface{}后,只要通过断言就可转换成其他数据类型
	int_value, ok := inter_value.(int)
	if ok {
		fmt.Printf("int_value=%v,int_value type=%T\n", int_value, int_value)	
	}
}

func main() {
	var number int = 10
	reflectInt(number)
}
结果
[ `go run reflect.go` | done ]
	re_int_type=int
	re_int_value=reflect.Value,re_int_value=10
	num=20
	inter_value=10,inter_value type=int
	int_value=10,int_value type=int

 备注:结构体的反射基本和上代码一致不再举例

五:反射使用细节

①:reflect.Value.kind()返回的是常量;

②:Type和Kind的区别

  Type是类别,Kind是类型,Type和Kind可能相同,可能不相同

  相同如:var num int num的Type是int,num的Kind也是int

  不同如:var struct1 Sturct1 struct1是结构体变量,这时Type是包.Struct1,Kind是struct

③:使用反射方式获取变量值且返回对应类型,要求数据类型匹配,比如x是int,则必须使用reflect。num := 10 + re_int_value.Int(),就是这类应用

④:通过反射修改变量

package main

import (
	"fmt"
	"reflect"
)

func reflectInt(i interface{}){
	re_val := reflect.ValueOf(i)
	fmt.Printf("re_val=%T\n", re_val)
	re_val.Elem().SetInt(20)
	fmt.Printf("re_val=%v\n", re_val)
}

func main() {
	var number int = 10
	reflectInt(&number)
	fmt.Printf("number=%v\n", number)
}
结果
[ `go run reflect.go` | done ]
	re_val=reflect.Value
	re_val=0xc00004e080
	number=20

 六:常量

①:与其他编程语言的区别

Go常量并不像其他编程语言,建议常量都是大写字母,但在Go中并没有这类建议;

当常量的名称首字母的大小写作用任然关系到访问的范围;

②:Go常量的声明

package main

import (
	"fmt"
)


func main() {
	//常量声明的同时必须赋值
	//const i int =10
	const (
		a = iota
		b
		c = 10
		d
		e = iota
	)
	fmt.Printf("a=%v,b=%v,c=%v,d=%v,e=%v", a, b, c, d, e)
}
结果
	a=0,b=1,c=10,d=10,e=4

猜你喜欢

转载自www.cnblogs.com/louis181214/p/10332264.html