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複製代碼
相關文章
相關標籤/搜索