golang中的反射
生活随笔
收集整理的這篇文章主要介紹了
golang中的反射
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
變量的內在機制
反射機制就是在運行時動態(tài)的調用對象的方法和屬性,官方自帶的reflect包就是反射相關的,只要包含這個包就可以使用。
多插一句,Golang的gRPC也是通過反射實現的。
反射與空接口
空接口可以存儲任何類型的變量
那么給你一個空接口,怎么判斷里面存儲的是什么東西?
在運行時動態(tài)的獲取一個變量的類型和值信息就叫反射
內置包: reflect
獲取類型信息: reflect.TypeOf
獲取值信息: reflect.ValueOf
反射種類(kind)定義
Go程序中的類型(Type)指的是系統(tǒng)原生數據類型,如int、string、bool、float32等類型,以及使用type關鍵字定義的類型,這些類型的名稱就是其類型本身的名稱。例如使用typeAstruct{}定義結構體時,A就是struct{}的類型。種類(Kind)指的是對象歸屬的品種,在reflect包中有如下定義
type Kind uintconst (Invalid Kind = iota // 非法類型Bool // 布爾型Int // 有符號整型Int8 // 有符號8位整型Int16 // 有符號16位整型Int32 // 有符號32位整型Int64 // 有符號64位整型Uint // 無符號整型Uint8 // 無符號8位整型Uint16 // 無符號16位整型Uint32 // 無符號32位整型Uint64 // 無符號64位整型Uintptr // 指針Float32 // 單精度浮點數Float64 // 雙精度浮點數Complex64 // 64位復數類型Complex128 // 128位復數類型Array // 數組Chan // 通道Func // 函數Interface // 接口Map // 映射Ptr // 指針Slice // 切片String // 字符串Struct // 結構體UnsafePointer // 底層指針 )Map、Slice、Chan屬于引用類型,使用起來類似于指針,但是在種類常量定義中仍然屬于獨立的種類,不屬于Ptr。type A struct{}定義的結構體屬于Struct種類,*A屬于Ptr
TypeOf和ValueOf
func reflect_example(a interface{}) {t := reflect.TypeOf(a)fmt.Printf("type of a is %v\n", t)v := reflect.ValueOf(a)fmt.Printf("value of a is %v\n", v)k := t.Kind()fmt.Println(k)}func main() {var x int64 = 3reflect_example(x) }運行時修改值
func reflect_example(a interface{}) {v := reflect.ValueOf(a)k := v.Kind()switch k {case reflect.Int64:fmt.Printf("a is int64, store value is: %d\n", v.Int())case reflect.Float64:fmt.Printf("a is Float64, store value is: %f\n", v.Float())case reflect.Ptr://指針類型 .Elem()相當于 指針取值v.Elem().SetFloat(22.5)fmt.Println("指針")default:fmt.Println("default")} }func main() {var x float64 = 3.4reflect_example(&x)fmt.Println(x) } var x float64 = 3.4 //這邊要傳地址,不然反射的是副本,下面修改副本的值會報錯 v1 := reflect.ValueOf(&x)//這邊已經是指針,要用Elem,通過Elem()獲取指針指向的變量,從而完成賦值操作 v1.Elem().SetFloat(4.3) fmt.Println(v1.Elem().Float())結構體屬性
type Student struct {Name stringSex intAge int//abc string }func main() {var s Studentv := reflect.ValueOf(s)t := v.Type()kind := t.Kind()fmt.Println(kind) //struct//查看字段數量,包含私有字段fmt.Println(v.NumField())//注意,私有獲取不到,會報錯的for i := 0; i < v.NumField(); i++ {field := v.Field(i)fmt.Printf("名字: %s 類型: %v 值: %v\n", t.Field(i).Name, field.Type(), field.Interface())}//修改結構體內部的值v1 := reflect.ValueOf(&s)//用索引方式v1.Elem().Field(0).SetString("abc")//指定名稱方式v1.Elem().FieldByName("Sex").SetInt(2)v1.Elem().FieldByName("Age").SetInt(12)fmt.Println(s) }輸出
struct 3 名字: Name 類型: string 值: 名字: Sex 類型: int 值: 0 名字: Age 類型: int 值: 0 {abc 2 12}結構體方法
func (s *Student) Test() {fmt.Println("this is test") }func main() {s := Student{23, "skidoo"}v := reflect.ValueOf(&s)t := v.Type()v.Elem().Field(0).SetInt(100)fmt.Println("method num: ", v.NumMethod())for i := 0; i < v.NumMethod(); i++ {f := t.Method(i)fmt.Printf("%d method, name: %v, type: %v\n", i, f.Name, f.Type)} }輸出
method num: 1 0 method, name: Test, type: func(*main.Student)調用結構體方法
type Student struct {A intB string }func (s *Student) Test() {fmt.Println("this is test") }func (s *Student) SetA (a int) {s.A = a }func main() {s := Student{23, "skidoo"}//要引用傳遞,不然修改的是副本會報錯v := reflect.ValueOf(&s)m := v.MethodByName("Test")var args1 []reflect.Valuem.Call(args1)setA := v.MethodByName("SetA")var args2 []reflect.Value//參數args2 = append(args2, reflect.ValueOf(100))setA.Call(args2)fmt.Printf("s: %#v\n", s) }輸出
this is test s: main.Student{A:100, B:"skidoo"}獲取結構體中的tag信息
type Student struct {F string `species:"gopher" color:"blue" json:"f"` }func main() {s := Student{}//要引用傳遞,不然修改的是副本會報錯v := reflect.TypeOf(s)field := v.Field(0)fmt.Println(field.Tag.Get("color"), field.Tag.Get("species"), field.Tag.Get("json"))復制
輸出
blue gopher f總結
以上是生活随笔為你收集整理的golang中的反射的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: golang中的plugin包
- 下一篇: golang中的TestMain