Go反射机制Reflect

参考文章:

Go语言中反射包的实现原理(The Laws of Reflection)json

和Java语言同样,Go也实现运行时反射,这为咱们提供一种能够在运行时操做任意类型对象的能力。Go是静态类型化的。每一个变量都有一个静态类型,也就是说,在编译的时候变量的类型就被很精确地肯定下来了,好比要么是int,或者是float32,或者是MyType类型,或者是[]byte等等。bash

一、第一反射定律(接口值到反射对象的反射)TypeOf和ValueOf

在Go的反射定义中,任何接口都会由两部分组成的,一个是接口的具体类型,一个是具体类型对应的值。好比var i int = 3 ,由于interface{}能够表示任何类型,因此变量i能够转为interface{},因此能够把变量i当成一个接口,那么这个变量在Go反射中的表示就是<Value,Type>,其中Value为变量的值3,Type变量的为类型int函数

reflect.Typeof获取具体的类型;reflect.Valueof获取接口的value。
ui

type Myint int

type User struct {
	name string 
	age int
}

func main() {
	u := User{name:"lyd",age:24}
	var num Myint = 18
	t := reflect.TypeOf(u)        //main.User
	v := reflect.ValueOf(u)       //{lyd 24}
        t_num := reflect.TypeOf(num)  //main.Myint
        v_num := reflect.ValueOf(num) //18
}
//还能够这样打印
fmt.Printf("%T\n",u)
fmt.Printf("%v\n",u)
v.Type() //main.User复制代码

二、将reflect.Value转原始类型(第二反射定律)

上面的例子咱们能够经过reflect.ValueOf函数把任意类型的对象转为一个reflect.Value,给定一个reflect.Value,咱们能用Interface方法把它恢复成一个接口值;spa

type Myint int

type User struct {
	name string 
	age int
}

func main() {
	u := User{name:"lyd",age:24}
	var num Myint = 18
	v := reflect.ValueOf(u) 
	v_num := reflect.ValueOf(num)

	y := v.Interface().(User)
	//fmt.Println能够处理interface{}, 因此能够直接
	y_num := v_num.Interface()

	fmt.Println(y,y_num) //{lyd 24} 18 

}

复制代码

三、修改反射对象的值(第三反射定律)

reflect.ValueOf函数返回的是一份值的拷贝,因此前提是咱们是传入要修改变量的地址。 其次须要咱们调用Elem方法找到这个指针指向的值。
指针

Value为咱们提供了CanSet方法能够帮助咱们判断Value的settablity code

一:反射对象不是settable的cdn

func main() {
	var x float64 = 3.4
	v := reflect.ValueOf(x)
	v.SetFloat(7.1) // Error: will panic.
}
复制代码

func main() {
	var x float64 = 3.4
	v := reflect.ValueOf(x)
	fmt.Println("settability of v:", v.CanSet())  //settability of v: false
}
复制代码

var x float64 = 3.4
p := reflect.ValueOf(&x) // Note: take the address of x.注意这里哦!咱们把x地址传进去了!
fmt.Println("type of p:", p.Type())  // type of p: *float64
fmt.Println("settability of p:", p.CanSet())  //settability of p: false
复制代码

反射对象p不是settable的,可是咱们想要设置的不是p,而是(效果上来讲)*p。为了获得p指向的东西,咱们调用Value的Elem方法

二:总之,下面这样才是能够改变值的

func main() {
	x:=2
	v:=reflect.ValueOf(&x)
	v.Elem().SetInt(100)
	fmt.Println(x)
}复制代码

四、获取底层类型

type User struct {
	name string 
	age int
}

func main() {
	u := User{name:"lyd",age:24}
	t := reflect.TypeOf(u)        
	v := reflect.ValueOf(u)      
	fmt.Println(t.Kind(),v.Kind()) //struct struct
}
复制代码

五、遍历字段和方法

经过反射,咱们能够获取一个结构体类型的字段,也能够获取一个类型的导出方法

type User struct {
	name string 
	age int
}

func main() {
	u := User{name:"lyd",age:24}
	t := reflect.TypeOf(u)        
	for i:=0;i<t.NumField();i++ {
		fmt.Println(t.Field(i).Name) 
	}
}
//name
//age复制代码

//方法
for i:=0;i<t.NumMethod() ;i++  {
	fmt.Println(t.Method(i).Name)
}复制代码

六、动态调用方法


七、JSON字符串对象与struct转换

a:JSON字符串转struct

type User struct {
	Name string 
	Age int 
}

func main() {
	var user User
	h := `{"Name":"lyd","Age":22}`
	err := json.Unmarshal([]byte(h),&user)
	if err != nil {
		fmt.Println(err)
	}else{
		fmt.Println(user) //{lyd 22}
	}
}
复制代码

b:struct转JSON

type User struct {
	Name string 
	Age int 
}

func main() {
	user := User{Name:"lyd",Age:22}
	newJson,_ := json.Marshal(&user)
	fmt.Println(string(newJson))  //{"Name":"lyd","Age":22}
}
复制代码

八、反射获取字段tag

func main() {
	user := User{Name:"lyd",Age:22}
	t := reflect.TypeOf(user)
	for i:=0;i<t.NumField();i++ {
		idx := t.Field(i)
		fmt.Println(idx.Tag)
	}
}
//name
//age复制代码

Tag的键值对

type User struct {
	Name string `json:"name"`
	Age int `json:"age"`
}

func main() {
	user := User{Name:"lyd",Age:22}
	t := reflect.TypeOf(user)
	for i:=0;i<t.NumField();i++ {
		idx := t.Field(i)
		fmt.Println(idx.Tag.Get("json"))
	}
}
//name 
//age复制代码
相关文章
相关标签/搜索