Golang的reflect
文章目錄
- 1. 概述
- 2. 反射類型對象
- 3. 反射的值對象
- 4. 反射修改值
- 5. 綜合Demo
1. 概述
Go語言提供了一種機制,能夠在運行時更新變量和檢查它們的值、調用它們的方法和它們支持的內在操作,而不需要在編譯時就知道這些變量的具體類型。這種機制被稱為反射。反射也可以讓我們將類型本身作為第一類的值類型處理。
2. 反射類型對象
使用reflect.TypeOf() 函數獲取任意變量的類型對象 reflect.Type
**函數的源碼如下 : **
// TypeOf returns the reflection Type that represents the dynamic type of i. // If i is a nil interface value, TypeOf returns nil. func TypeOf(i interface{}) Type {eface := *(*emptyInterface)(unsafe.Pointer(&i))return toType(eface.typ) }通過獲取的類型對象就能訪問原變量的類型信息
在類型信息中我們需要知道 類型(Type) 和 種類(Kind)的區別
類型 Type : 通常指的是系統中的原生數據類型和使用type 關鍵字定義的類型,通過類型對象 reflect.Type中的Name() 方法獲取
種類Kind : 指定的對象的根本種類,是更高一層的概括,通過reflect.Type 中的 Kind() 函數獲取
- Type的值和Kind的值可能相同,也可能不相同
go run main.go
Type = char Kind = string Type = dogs Kind = struct Type = string Kind = string Type = Kind = ptr Type = dogs Kind = struct當一個變量是結構體實例的時候,怎么通過反射獲取類型信息呢?
通過 reflect 包中reflect.type的 Field() FieldByIndex FieldByName FieldByNameFunc 方法獲取的 StructField 結構體有些什么內容呢?
// A StructField describes a single field in a struct. type StructField struct {// Name is the field name.Name string// PkgPath is the package path that qualifies a lower case (unexported)// field name. It is empty for upper case (exported) field names.// See https://golang.org/ref/spec#Uniqueness_of_identifiersPkgPath stringType Type // field typeTag StructTag // field tag stringOffset uintptr // offset within struct, in bytesIndex []int // index sequence for Type.FieldByIndexAnonymous bool // is an embedded field } package mainimport ("fmt""reflect" )type dogs struct {Name string `json:"name"`Age int8T int `json:"t" id:"99"` } func main(){// 創建實例Hachiko := dogs{Name:"Hachiko",Age:int8(2),T:66}//獲取反射對象實例typeD := reflect.TypeOf(Hachiko)// NumField()函數,返回結構體成員的數量for i:=0;i<typeD.NumField();i++{// 獲取結構體成員的類型// Field()函數 根據索引返回結構體對應field的信息typeOfField := typeD.Field(i)// 輸出成員字段名稱和tag(標簽信息),成員類型fmt.Printf("%s , %v,%s\n",typeOfField.Name,typeOfField.Tag,typeOfField.Type)}// 通過結構體字段名獲取其類型信息// FieldByName()函數,根據字段名返回字段信息if fieldType,ok := typeD.FieldByName("T");ok{fmt.Println(fieldType.Tag.Get("json"),fieldType.Tag.Get("id"))} }go run main.go
Name , json:"name",string Age , ,int8 T , json:"t" id:"99",int t 993. 反射的值對象
反射可以動態的獲取或者設置變量的值
Go語言中使用reflect.Value獲取和設置變量的值
go run main.go
a ==> int,99 b ==> int,99 c ==> int32,99 package mainimport ("fmt""reflect" )type demo struct {a intb stringc boolfloat64d [5]int }func (d *demo) dF1() {fmt.Println(d.a) } func (d *demo) dF2() {fmt.Println(d.b) }func main() {t := demo{99, "golang", true, 98.90, [5]int{1, 2, 3, 5, 6}}// 獲取值對象valueOfT := reflect.ValueOf(t)// NumField()是獲取字段數量fmt.Println(valueOfT.NumField()) // 5// 獲取索引為1的字段fieldOf1 := valueOfT.Field(1)// 打印該值對象的類型fmt.Println(fieldOf1.Type()) // string// 通過字段名查找fieldOfd := valueOfT.FieldByName("d")fmt.Println(fieldOfd.Type()) // [5]int }go run main.go
5 string [5]int4. 反射修改值
reflect.Value 也提供了修改版值的方法
package mainimport ("fmt""reflect" )func main() {var age int8 = 99// 獲取一個值對象valueOfAge := reflect.ValueOf(&age)// Elem() 對可尋值的元素獲取它的值// Addr() 對可尋址的元素獲取它地址// CanSet() bool 返回元素(值對象)是否能被設置// CanAddr() bool 返回元素(值對象)是否能被尋址valueOfAge = valueOfAge.Elem()valueOfAgeAddr := valueOfAge.Addr()fmt.Println(valueOfAge) // 99fmt.Println(valueOfAgeAddr) // 0xc000054080fmt.Println(valueOfAge.CanSet()) // truefmt.Println(valueOfAge.CanAddr()) // true// SetInt() 使用int64設置值// SetUint() 使用uint64設置值// SetFloat() 使用float64設置值// SetBool() 使用bool設置值// SetBytes() 設置字節數組[]bytes值// SetString 設置字符串值valueOfAge.SetInt(1)fmt.Printf("age type= %T, value= %v",age,age) }go run main.go
99 0xc000054080 true true age type= int8, value= 15通過類型創建類型實例
package mainimport ("fmt""reflect" )func main(){var i int = 99// 獲取反射類型對象typeOfI := reflect.TypeOf(i)// 根據反射類型對象創建類型實例newI := reflect.New(typeOfI)// 答應類型和種類fmt.Println(newI.Type(),newI.Kind()) //*int ptr }5. 綜合Demo
package mainimport ("fmt""log""reflect" )type Person struct {Name string `json:"name"`Age int `json:"age"`Sex string `json:"sex"` } func (p Person) PersonSet(name string,age int,sex string){p.Name = namep.Age = agep.Sex = sexfmt.Println(p) } func (p Person) ShowPerson(){fmt.Println(p) } func reflectOfStruct(a interface{}){// 獲取reflect.Type類型typeObj := reflect.TypeOf(a)// 獲取reflect.Value類型valueObj := reflect.ValueOf(a)// 獲取Kind類別,下面兩種方法都能獲取KindType := typeObj.Kind()//KindValue := valueObj.Kind()//fmt.Println(KindType)//fmt.Println(KindValue)if KindType != reflect.Struct{log.Fatal("Kind is not error")return}// 獲取字段數量fieldsNum := valueObj.NumField()for i:=0;i<fieldsNum;i++{fmt.Printf("field %d %v\n",i,valueObj.Field(i))// 獲取指定的標簽值tagValue := typeObj.Field(i).Tag.Get("json")if tagValue != ""{fmt.Printf("field %d tag = %v\n",i,tagValue)}}// 獲取方法數量MethodNum := valueObj.NumMethod()fmt.Printf("has %d methods\n",MethodNum)// 調用第一個方法valueObj.Method(1).Call(nil)// 對有參數的方法調用var params []reflect.Valueparams = append(params,reflect.ValueOf("lisi"))params = append(params,reflect.ValueOf(88))params = append(params,reflect.ValueOf("man"))// 傳遞參數,調用指定方法名的方法valueObj.MethodByName("PersonSet").Call(params) } func main() {var a Person = Person{Name:"zhangsan",Age:99,}// 調用函數reflectOfStruct(a) }go run main.go
field 0 zhangsan field 0 tag = name field 1 99 field 1 tag = age field 2 field 2 tag = sex has 2 methods {zhangsan 99 } {lisi 88 man}總結
以上是生活随笔為你收集整理的Golang的reflect的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cad2004教程_天正2014软件安装
- 下一篇: ADODB.Stream